Android and Linux

Wednesday, December 21, 2011

Woe is me...

Since getting the Galaxy Nexus, I've had a little trouble and have been flashing ROMs like crazy and spending enough time in recovery that I could have put Betty Ford's kids through college. Wait... I'm not sure that made sense.

Anyway, I assumed the problems were from hacks being rushed to the public with little testing, but I think I actually got a lemon and am going to swap it for a new one.

To begin with, I kept losing root after an hour or two for some unknown reason. I noticed that the file manager I was using was registering battery usage almost as high as the display after one such unrooting, so I stopped using it. That helped me get through a day or two with root intact, but I'm not entirely sure that was the problem because I was working in the terminal last night and lost root again.

I've also had random shutdowns and really bad slowdowns, and I've spend a couple of days trying, and failing, to get ssh to work. Oddly, I can ssh from the phone to my computer from anywhere on the cell network, but it simply will not work when connected to my router.

On the router, I had assigned the phone a certain IP address but it seemed to connect at a different one for the past few days. I kept setting it, thinking maybe I had kept forgetting to hit "apply" or something, until I finally realized tonight that I had set it yesterday for a different MAC address.

A little investigation revealed that my phone's MAC address changes on every boot. Oops, MAC addresses aren't supposed to do that! It's a pretty neat trick but not only troublesome for IP reservation, but could be causing a lot of other problems as well.

I found someone else on XDA who had the same problem and Samsung said it was a hardware problem and swapped it for him. Verizon's phone number is right there on the charger and I didn't know Samsung's so I called the big V and they were a little puzzled. They called Samsung and they were puzzled too, but the Verizon guy told me to swap it.

I'm going to swap it at the store tomorrow so I don't have to wait for one to be shipped.

It nearly brought a tear to my eye, but I just typed "fastboot oem lock" in a terminal and brought my phone back to stock. But hopefully I'll be ready to start playing with the GNex for real after tomorrow.

Sunday, December 18, 2011

Galaxy Nexus

I finally got a Galaxy Nexus. I went Thursday at 11:15, walked in and told them I wanted a Galaxy Nexus and they said "We don't have them yet. They're coming in via UPS today. We're getting 8 of them and can save one for you if you want."

Yes, I live in a small town.

I didn't get around to buying one until yesterday afternoon. Since I enjoy voiding warranties within an hour of purchase, I promptly rooted it but didn't have time to do much else. Last night, I was a little upset because I kept losing root. I still don't know what the problem was, I'd flash the recovery and su binary and I would be doing something as root in a terminal when suddenly it would tell me "only root can do that" and I could no longer su. The root checker app said I had root, and the superuser app showed that certain apps were allowed and logged them as allowed when I opened them, but they still reported that they couldn't gain root.

It kept losing root after numerous flashes and rootings until I flashed this ROM this morning, and that seems to have cleared it up.

Anyway, my impressions on the Galaxy Nexus...

This puppy is huge! I'm charging the battery on my digital camera to try to get some comparisons of the Nexus One and Galaxy Nexus, but if you want a good idea of the size, it's almost the exact same size as a dollar bill, except a little shorter.

You ever go to a cell phone store and look at the flip phones and think "awww, such cute little screens, but I don't know how you could get anything done on that tiny little window." I felt that way when picking up the N1 after 20 minutes with the GNex.

The N1 had a habit of turning in my pocket, the GNex stands tall and it's thinner, so although it's much larger, it rides in my pocket better than the N1.

There are some things I don't really like.

The phone has very few features and it's easy to pull it out of your pocket and try to use it upside down. The earplug is on the bottom, which may or may not be a good thing, I'm not really sure yet.

The battery cover is a cheap piece of plastic that snaps in place instead of sliding. It's not what I would have designed, but it does raise the possibility of easy replacement, so there may be some cool looking battery covers showing up soon.

There are no hardware buttons for "back" "menu" "home" and "search", instead there are software buttons for "back" "home" and "recent apps". Three small dots are used for settings, and they may be at the top or the bottom of an app. I miss being able to always find them in one place.

And no trackball. Oh, how I miss that, but no other phones have them either. I've really been dreading the loss of the trackball, but I'll have to adapt.

With the launcher, you can't add widgets by long pressing the home screen, you have to do it from the app drawer. The app drawer has tabs for apps and widgets, and everything side scrolls now, which takes some getting used to.

LauncherPro still works, so that gives you the old school feel with long press widget adds etc, but it hasn't had an update in forever so it will surely stop working one of these days and old fogies like me will be dragged kicking and screaming into the future.

I really do love the phone. My gosh, when I pull that thing out it feels like I'm using a tablet. I have a lot of setup to do to get things working the way I want, so that means a lot of playing with this cool phone!

Monday, December 12, 2011

Android blues... and cheers.

The bad.

My Nexus One is dying. About a month ago, I was having problems like my favorite keyboard kept being reset to the Android default and my email sync kept turning off for no reason. So I upgraded to the newest Cyanogen and had even more problems. First it took several attempts to install, then a couple more wipes and attempts and some tweaking, hacking and tricking to get the Market to work, and I've been having random reboots and lock-ups since.

When you have a broken power button, a random lock up means you have to plug it into a charger then pull and insert the battery a couple of times to trick the sucker into booting.

I'm pretty sure there is something wrong with the phone's hardware somewhere. The upside is that it gives me an excuse to get the new Galaxy Nexus. The downside is that Verizon is dragging their feet about putting the darn thing on sale, so I'm stuck with a dying N1 for the time being.

There's nothing cooler than having to leave a party to go outside and plug my phone into the car charger to tease it into a hard reboot when it suddenly locks up in the middle of a conversation.

The Good.

If you haven't been to the web version of the Android Market lately, they've added some handy filters to search results, and they're also having 10 cent app sales to celebrate their 10 billionth download. The downloads have been changing daily and there are quite a few worth picking up. I've grabbed a bunch because, although I don't really want them now, I may have a use for them in the future.

Sunday, October 30, 2011

Run Tasker task from command line

I have been looking for an alternative to Notify My Android in order to send myself notifications to my phone when I'm at home. NMA notifications work fine, but you have to open the app to clear them and I just wanted a vibration or sound that didn't leave anything else on the phone for when a job finished at the computer or something.

I first looked at playing a media file with the following command:

am start -n com.android.music/com.android.music.MediaPlaybackActivity -d /sdcard/foo.mp3

That sorta works. It opens the media app and plays the file then immediately goes to the next song. Adding && sleep 1 && pkill com.android.music makes it work more like I wanted, but that's too ugly.

I ran across this post in the Tasker forum about invoking a task from the command line, but the consensus was that it wouldn't work unless the command line app has the right permissions.

But then I discovered that this works:

am broadcast -a net.dinglisch.android.tasker.ACTION_TASK -e task_name YOUR_TASK_NAME

The only difference being the "-e" option instead of "-es."

So I made a simple script called "task" for the phone.
#! /system/bin/sh
am broadcast -a net.dinglisch.android.tasker.ACTION_TASK -e task_name "$*"
Now I can bounce the command off the phone via ssh and run any Tasker task I want.

Wednesday, October 19, 2011

The Pogoplug is taking over my life

The $50 Pogoplug that I bought to goof around with is now my main server.



The Pogoplug is about the size of a small, thick book. To the right is an Edge DiskGo network attached storage drive. That's where I keep all my media to be played on the TV via the Roku and the MyMedia Server Roku app. The Pogoplug is running a small python server that acts as the companion to the Mymedia app and I simply mounted the drive over the network because I didn't have any USB cables to plug it in directly, so it acts as if it is serving the files from it's own drive.

Debian is installed on the USB stick in the front of it. The white cable in the back is the power cord, and there's a cat5 plugged into the back which you can't see, and the two black cords are USB cords running to my CM11A and W800RF32A, which are an X10 controller and wireless receiver respectively.

It's not only serving media and running the automation, but other scripts to check weather, watch my IP address, back up files from my phone when I connect to my home wifi, etc. Everything installed and runs just as easily as it would on any desktop Linux. The only hard part was getting accustomed to Debian, but it's not so different from Slackware and at least it's not Ubuntu.

That's the beauty of Linux, very small programs requiring very little resources can do as much, if not more, than some $100 program you'd have to buy for a Windows computer, and they can do it in the background without you having to be there to point and click, and they can do it on very minimal hardware.

Thursday, October 13, 2011

remote ssh to multiple hosts on same network in Android

I have four devices running ssh at home. Since they're all attached to my router, they all have the same IP address to the outside world, but ssh runs on different ports on each device. In theory, you can ssh into each one by specifying the correct port. In practice, however, it's not always that simple, especially with Android.

In order to prevent a man-in-the-middle attack, when ssh makes a connection, it saves the computer's IP and host key in the ~/.ssh/known_hosts file and the next time you try to connect, it checks the IP in that file to make sure the host key is the same.

Let me illustrate. Let's say my home IP address is 123.45.54.321. I have 2 devices, comp1 and comp2 running ssh on port 111 and 222, respectively. And let's just say their host keys are AAA and BBB (the keys are actually much, much longer). If I ssh into 123.45.54.321 port 111, then this gets entered into the known_hosts file: 123.45.54.321 AAA.

Now, if I try to ssh into comp2 at 123.45.54.321 port 222, it gets the host key BBB from the computer and looks in the known_hosts file and says, "whoa, I expected AAA from the computer at 123.45.54.321, something is wrong" then the connection fails.

There are normally a couple of solutions for this. First, you can sometimes connect to comp1, copy the key from known_hosts then remove it from the file and connect to comp2. Now put the comp1 key back in known hosts. I've never done this and heard that it doesn't always work, but sometimes ssh will keep trying entries in known_hosts until it gets one right.

The better solution is to set up ssh config file like so:

Host comp1
Hostname comp1.somedomain.com
Port 111
HostKeyAlias = comp1
CheckHostIP = no

Host comp2
Hostname comp2.somedomain.com
Port 222
HostKeyAlias = comp2
CheckHostIP = no


Then you can connect with the command ssh comp1 or ssh comp2.

Unfortunately, that doesn't work with Android because it doesn't have an ssh config file. I'm not entirely sure you can do anything about it with the normal Android ssh program. I deleted it long ago and use the ssh binary from Better Terminal Emulator Pro (see this post) and there is a workaround with it.

The first trick doesn't work with the BTEP ssh binary, and neither does the second trick because it doesn't seem to use a config file. As often is the case with Android, the ugliest solution is the only solution.

BTEP looks for the known_hosts file in /data/data/com.magicandroidapps.bettertermpro/home/.ssh (sorry, I originally posted the wrong directory. Fixed now!). You can use the first trick to get a copy of the host keys, then write a script to overwrite known_hosts depending on which computer you want to connect to.
#! /system/bin/sh

case "$1" in

comp1)
echo "$(hip) ssh-rsa AAA==" > /data/data/com.magicandroidapps.bettertermpro/home/.ssh/known_hosts
ssh USER@$(hip) -i PATH/TO/KEYFILE -p PORT;;

comp2)
echo "$(hip) ssh-rsa BBB==" > /data/data/com.magicandroidapps.bettertermpro/home/.ssh/known_hosts
ssh USER@$(hip) -i PATH/TO/KEYFILE -p PORT;;

esac
You would fill in your user, path to the ssh key and port number. You can also fill in the IP address, but that's what the $(hip) part does. hip is a script that tells me my home computer's IP address which I've blogged about here and here. Essentially, I keep my home IP address in a file and the hip command just displays that file. That way, I don't need to hard code my IP in any scripts. If my IP changes, I can just update it in that file and not worry about changing the scripts.

I named the script above simply "s". So, if I run s comp2, it will write 123.45.54.321 ssh-rsa BBB== to known_hosts then connect to comp2.

Incidentally, this also takes care of another problem- IP changes. The first time you connect to a host, ssh asks if you really want to connect and you have to type yes or no.

If you normally have 123.45.54.321 ssh-rsa BBB== in your known_hosts file and your home IP changes for some reason, the new IP won't be in the file and your scripts will break until you manually log in and tell ssh yes or no. But now that no longer matters because we are controlling known_hosts and filling it with the correct up-to-date IP and associated key.

The other solutions are better for computers that are running the real OpenSSH, but this is the only solution I could figure out for Android and it's funky programs.

Tuesday, October 11, 2011

Pogoplug

I was in Best Buy today and noticed that they sell Pogoplugs for $50 so I picked one up. I believe it is the first generation without wifi, but I don't care about that, I prefer using network cable when available over wifi anyway. The downside to Pogoplugs is that they have very little space available on them, but you can install Linux on an external hard drive plugged into them via USB. I didn't have an external drive, per se. I have a NAS network drive, and that may work, but I didn't have a USB cord to attach it, so I installed Linux on a USB stick for the time being.

Using this guide, it only took a few minutes to have a very minimalistic version of Debian running on it, and after installing the gcc compiler and other tools, I was able to install Heyu. Then I plugged my CM11A X10 controller into the Pogoplug and was a little surprised that the darn thing actually worked. Awesome!

The NAS drive is what I use to store videos for streaming to the Roku. I tried to install the server program on the Pogoplug using the USB stick just to see if it would work, but python threw socket errors for some reason. I'm going to investigate whether I can use the NAS with the Pogoplug. If not, I'll probably get an external drive and use it to serve videos, control the home automation, and various other things I have a computer doing now. I'm not entirely certain I want to turn over everything to a little box like this, but I want to do it to see for myself that it can be done, then change back to the computer if I prefer it.

I think it's pretty amazing that, for $50, you can get a computer the size of a book that can do all this. Then again, the Raspberry Pi.org/ is only going to be $25, so maybe I got ripped off!

Friday, October 7, 2011

Yay, new computer.

I bought a new computer and, boy, why didn't someone tell me computers had gotten so darn good these days? My main desktop was a 2.2 GHz box with 2 gigs of ram. That's pretty outdated but was enough for everything I needed, but I wanted to turn it into a server and get a new one for general use. Now I have an i7 quad core with eight 3.3Ghz processors. What a difference!

Since I got the Roku, I found myself wanting to encode videos to play on it. With the old computer, encoding a 175mb 30 minute TV show took about 45-50 minutes and the fans on the computer sounded like a jet trying to take off. And movies? They weren't worth spending hours to encode.

The new computer? It can encode a TV show in 1-2 minutes and a 3 Gig HD movie in 15-30 minutes and it doesn't make a sound the entire time.

I've had it for a couple weeks, but soon after getting it, half of my home automation stopped working. I finally figured out that the computer was to blame. The instant the power cord is plugged into the computer, it causes interference that drowns out the X10 signals. I ordered a noise filter that finally arrived so now I can leave it plugged in as long as I want and still have my automation working.

Anyway, I've been slowly setting up the old computer to act as a server. It isn't a lot of work, it was really a desktop/server before, but I need to get everything set up so I can stick it in a closet somewhere and forget about, administering it from the new computer when needed.

I should have a lot to post about soon. I have a transceiver for my home automation on the way in order to pick up RF signals. With it, I will be able to set up motion detectors and things that can send a signal to the computer instead of only the other direction. Automation is only half useful without that.

I'm also planning to start toying around with plug computing. A plug computer is a full fledged linux computer that fits in a box the size of an electric plug. With the right setup, I could do away with my computer that acts as a server and use a plug computer to run the automation, and mount a cheap hackable display like the Chumby in the house to control it all graphically, and of course Android to control it all remotely.

Anyway, sorry for not having much to post about but hopefully that will change soon.

Monday, September 19, 2011

Camera weather display

I'm sorry I haven't posted much in a while. To tell the truth, I haven't done much worth sharing. My daughter started kindergarten and I think her school is harder for the parents than the kids, and being a single dad makes it all the more tough. The only time I have for myself is a couple hours after she goes to bed and the housework ain't doin' itself during that time.

Oh well, I did come up with something pretty cool that will probably be of no use to anyone unless they have the same gadgets as me. It may inspire someone to do something similar with other gadgets though.

Taking my Foscam and Roku scripts and a Roku app, I made a little automated camera/weather display for my TV.

The Roku app is MyMedia which allows you to play files from your computer on your TV. It's two parts, a simple server for your computer and an app on the Roku. The server shares Music, Photo and Video folders to your local network where the MyMedia app on the Roku can pick them up. There are other Roku apps which do the same thing, but this one fit my needs.

Once that is set up, the ID for that channel is 2542, so using my Roku script, you can use the command roku go 2542 to load that channel. Once it loads, you can use the script again to navigate to different folders using left/right and select commands. You can, of course, do this with the Roku remote control, but it's a lot cooler to automate it.

Let me back up and first post the script then walk through everything that is happening in 4 steps.
#! /bin/sh

cam snap

WX=$(links -dump 'URL' | grep -A 6 'Weather:' | sed -e 's/^[ \t]*//')

convert /sdcard/cam.jpg -fill white -gravity South -pointsize 25 -stroke '#000C' -strokewidth 2 -annotate 0 "$WX" -stroke none -fill white -annotate 0 "$WX" /sdcard/cam.jpg

roku right
roku go 2542; sleep 7
roku str right right select; sleep 1
roku select


Step 1: cam snap
Using the Foscam script, just run cam snap and a jpg will be saved wherever you have the script set up to save it. On my computer, I actually made a /sdcard directory so I could more easily write scripts that would work on both the computer and Android phone, so /sdcard/cam.jpg in this post is on the computer, not the phone.

Step 2: WX=$(links -dump...
Links is a command line Linux browser which can dump the text of a webpage. Lynx is another which is often interchangeable with Links, and both have the same -dump option so either could be used here. This sets the WX variable to the output of the links command. I used the weather conditions from the weather.gov mobile site. Click that, put in your zip code, click go, then click current conditions. Copy the URL of the current conditions page and use it to replace URL in this command in order to grab everything from Weather to Visibility then align the text properly. This is just an example, you could get the weather from anywhere.

Step 3: convert...
"convert" is part of Imagemagick, a powerful command line image manipulation program which is installed on most Linux distributions. In this case, I'm using it to write the weather from the WX variable on the image.

Step 4: roku...
All the Roku commands use my Roku script to navigate to the MyMedia channel and select the image. The first command is used to wake the Roku up in case the screen saver is on, the second selects the channel and waits for it to load, which usually only takes 3-4 seconds, and the rest navigate and select the image. I don't have any other images to display so when I navigate to the Photos folder and click "select", it automatically opens the image I want since it's the only one. If you have other photos, you may want to use a subdirectory and a couple extra commands to navigate to it.

Here is the end result:



I pointed the camera at a wall because the normal view would show part of my neighbor's house, and I would feel awkward about that. It's also dark, it looks much better pointed over my yard with the daytime sky in view. The image itself is mediocre on a computer, but looks great stretched out on a wide screen TV.

So, what use was all this? Well, I have a cron job scheduled to run at the same time my alarm goes off in the morning. It turns on a couple lights that are controlled with X10 automation, sends the weather forecast to my phone, and a couple other odd jobs. I added this to the schedule, so I can roll over, look at the TV and see what it looks like outside as well as the current weather conditions.

I also set up a Tasker task to ssh in to my home computer and run the first three steps, copy the resulting file to my phone, then display it, in case I'm interested in seeing this image and info while I'm away.

While this trick is pretty specific to my setup, maybe it will inspire someone with other gadgets to do something cool with whatever they have.

Sunday, August 28, 2011

Part 2: Finding the current song playing in Android, still sorta.

I made a post about getting the filename from the mediaserver at the Tasker discussion group and others found that the lsof utility only comes on Cyanogen so many people don't have it. I found an alternative in "ls -l /proc/$(pidof mediaserver)/fd" and I'll show some ways to use it below.

Another poster, Matthieu, also figured out a way to get the mp3 tags from the files. The ID3v1 tags are pretty simple, but ID3v2 is a pain. Here is a post I made to that thread incorporating the lsof alternative, Matthieu's method of extracting ID3v1 from that thread, and the start of an ugly method to get ID3v2 tags. More on that in a moment.

Here's an lsof alternative. I think it could do without the grep command but it's safer with it in:
ls -l /proc/$(pidof mediaserver)/fd | sort -g -k 9 | grep mp3 | tail -n1
This will give you the long filename like /sdcard/foo.mp3:
ls -l /proc/$(pidof mediaserver)/fd | sort -g -k 9 | grep mp3 | tail -n1 | awk '{print substr($0, index($0,$11))}'
This gives the short filename like foo.mp3:
basename "$(ls -l /proc/$(pidof mediaserver)/fd | sort -g -k 9 | grep mp3 | tail -n1 | awk '{print substr($0, index($0,$11))}')" .mp3
This gives the id3v1 tag:
tail -c 125 $(ls -l /proc/$(pidof mediaserver)/fd  | sort -g -k 9 | grep mp3 | tail -n1 | awk '{print substr($0, index($0,$11))}') | head - c30
This gives the id3v2 tag but needs tweaking:
grep -A 20 TIT2 "$(ls -l /proc/$(pidof mediaserver)/fd  | sort -g -k 9 | grep mp3 | tail -n1 | awk '{print substr($0, index($0,$11))}')" | grep -m 1 [a-z]
That last one is ugly and unfinished. ID3v2 tags are variable length and the length of the tag is supposed to be encoded in the file itself but, for the life of me, I can't find a file on my system that follows that guideline. I'm obviously missing something because they display correctly when played, but most of them also have ID3v1 tags on the end as well, so maybe that's why they display properly.

I would spend time trying to find a better solution but Pent said he is going to add mp3 tag support to Tasker soon and that should work better than anything I could come up with. Plus, I'm really not interested in the tags. When something interests me, I usually get about an hour late at night to work on it, and I only want the file name.

As ugly as it is, the last one still kinda works. All the tags on my system start with TIT2, but are followed by a lot of hex gibberish before the plain text tag begins. This greps TIT2 then greps the first line below it that contains a lower case letter. On my files, it has a high success rate. One big problem it has is that the tag is often followed by another field such as TALB, so the output can be "Song TitleTALB." Someone could figure out all the possible fields in an ID3v2 tag then just use sed to chomp them off. Or someone cou otu a more reliable method, or we can just wait for Tasker to do it for us.

Saturday, August 20, 2011

Finding the current song playing in Android, sorta.

I've seen people wanting to use Tasker to get the title of the currently playing song before, but it's not really possible because Android doesn't have an API for it. There is a semi-workable solution using the Locale Execute Plugin. We can find which files the media server has open with the lsof command. Assuming the only files you're interested in are mp3s, we can just grep the mp3s from the list and print the filename:
lsof -p $(pidof mediaserver) | grep -m 1 mp3 | awk '{print substr($0, index($0,$9))}'
As luck would have it, the current song seems to always be at the top of the list, so using grep -m 1 we can just get the first line of output.

Output: /mnt/sdcard/download/AloeBlacc-YouMakeMeSmile.mp3

It can be cleaned up a little with the basename command:
basename "$(lsof -p $(pidof mediaserver) | grep -m 1 mp3 | awk '{print substr($0, index($0,$9))}')" .mp3
Output: AloeBlacc-YouMakeMeSmile

If you're interested in files other than mp3, you can add them to the grep command:
grep -E -m 1 'mp3|wav|other1|other2'
The downside is that this just gets the file name and doesn't display any metadata or anything like that. If your file is Track10.mp3, it may show information about the artist and song in the media player, but with this trick it will only show Track10.

This trick also works to display the file being played in BeyondPod, the podcatcher app, but podcasts often don't follow naming schemes meant for humans so the output for the Jordan Jesse Go! podcast ends up being jjgo110814_ep187. If your goal was to display the file in Tasker or Zoom, you could set up replacement titles for your podcasts, like if the title matches jjgo*, display "Jordan Jesse Go!"

Aug 23: I edited the awk command to handle filenames with spaces, then I realized the awk command isn't needed. There's no need to pick out the field with the filename with awk. You can use the entire line, the basename command will only output whatever is to the right of the last "/" anyway. I'll leave the original up since it's been there for a couple of days and people have already seen it, but this simpler command would be better to use:
basename "$(lsof -p $(pidof mediaserver) | grep -m 1 mp3)" .mp3
Use that one instead, and I'll try to notice the obvious sooner next time.

Wednesday, August 3, 2011

Free Nexus S

If you go to google.com, there is a line of text that reads "Nexus S, a pure Google experience. Get it FREE today only"

It requires a 2 year contract or an extension of your existing contract. I wasn't impressed with the Nexus S when it came out but my Nexus One is seriously aging and I'm contemplating getting a Nexus S. I can't make up my mind because I want to wait for something better too. Oh well, in case you missed it, go to google.com and click the link.

Wednesday, July 20, 2011

New Tasker plugin

If you read this blog, you're probably interested in the new Secure Settings Tasker plugin. It has a lot of features which seem good. Unfortunately, I don't have a use for any of them except the shell command runner and I'm happy enough with my own methods that I probably won't change. But the plugin does allow you to store stdout and stderr in a Tasker variable and I'm sure will be a hit.

The downside is that you have to set up a "variable changed" profile to get the output (see the second post in that thread and the later reply). It's more or less the same as my command runner profile except it can display multiple lines of output and my profile can't because Tasker still can't read entire files. (I got it on the todo list, but it's been sitting there for nearly a year).

Plus, it has other features. If you're interested in those, it's probably a win-win.

Thursday, July 14, 2011

Notify My Android down

Wouldn't you know it, as soon as I start using and posting about Notify My Android, it stops working. According to an NMA Twitter post:
Google C2DM SSL Server certificate expired and they didn't update. It should be normalized later this morning. Sorry for that.
That was 16 hours ago. Hopefully they get it running soon.

Monday, July 11, 2011

Pulling data from Notify My Android notifications

Notify My Android (NMA) doesn't have Tasker integration, but we can bridge the gap... sorta.

Data for the app is stored in a database so we can pull out the ever handy sqlite3 and grab it.

sqlite3 /data/data/com.usk.app.notifymyandroid/databases/nma "SELECT * from notifications;"

The data is stored in pipe delimited fields with the newest record on top. Here is what it looks like when I send the output of the date command as both the event and description field.

44|141395|Home|Mon Jul 11 20:18:43 EDT 2011|Mon Jul 11 20:18:43 EDT 2011|1310430099|0|1

Assuming we want the 5th field, just tell Tasker to read the line, split the variable then flash %VAR5.

But here's the catch, Tasker can perform an action when the notification comes in but the data doesn't go into the file until a few seconds after the app is opened, after it syncs with it's home server.

The most elegant solution doesn't work. That would be a Tasker context watching for the file to be modified, then running the command to get the new notification. Unfortunately, watching for file modification doesn't seem to work in /data/data.

You could write a script to watch the file for new contents then put something in a file on the sdcard that Tasker could see, but it would be necessary to keep the script looping and if you lost the network connection or something, it could loop indefinitely. You could kill it once the app exits, but this is getting too complicated.

The easy answer is to just add a wait. You'll need a profile watching for the app to open, but disable that profile. Then have a profile watching for the notification. Once the notification comes in, have it enable the "App Open" profile. The App Open profile can carry out a task to

1 wait 5 seconds (adjust if your network connection takes longer)
2 execute: @! sqlite3 /data/data/com.usk.app.notifymyandroid/databases/nma "SELECT * from notifications;" > /mnt/sdcard/Tasker/notified
3 read line 1 of Tasker/notified to var %NOTIFIED
4 Variable Split %NOTIFIED splitter: |
5 flash %NOTIFIED5
6 Profile Status set Notified off

Remember, the NMA app must be opened for Tasker to grab the notification data, but with these profiles, when there isn't a notification, it can be opened without triggering the task.

%NOTIFIED5 will contain the main body of the notification. You can select from 3, 4 or 5. They are the application, event and description. All three are necessary to send a notification through NMA and can contain 256, 1000 and 10000 characters respectively. Only the application and as much of the event as possible show in the Android Notification area. The entire event and the description are shown in the app.

Pent has put the ability to read any file system-wide on Tasker's todo list. Until then, I hope someone gets some use out of this.

Sunday, July 10, 2011

Prowl-like custom Android push notifications

Oh boy, I've been wanting this forever. When I used the iphone a year and a half ago, there was an app called Prowl which allowed you to send any push notification to your phone. You could, for example, have your computer send a notification when it booted and the notifications could say anything up to a 1024 character limit.

I've really wanted that for Android and hoped to see it when Google came out with the Cloud to Device Messaging service but I didn't find it until now.

Notify My Android will allow you to send custom push notifications to your phone and here's how to use it from the Linux command line.

You first get the app from the Market then create an account on their website. Once you log in to the website, go to "my account" and generate an API key. Now it's as simple as crafting a cURL or wget command to post the data.

curl -k https://nma.usk.bz/publicapi/notify -F apikey="YOURKEY" -F application="Testing" -F event="test event" -F description="hello world"

wget -q -O - --post-data "apikey=YOURKEY&application=APPNAME&event=EVENT&description=this is the description area where the actual notification text is supposed to go" https://nma.usk.bz/publicapi/notify

The fields can be found on the website on the API page. cURL is easier to understand here because you just put a -F then the name of the field to post to and the text to post. -F apikey="YOURKEY" is pretty easy to decipher, but wget is actually doing the same thing, just differently.

One trick I always thought was useful was to set it up so you can pipe output to the phone. You can pipe output to this short script and it will show up on your phone. I include both wget and cURL. cURL is simpler to use on a computer but wget can be used on your phone, however, I've found that wgen on the phone doesn't allow secute https. You can still use regular unsecure http if you think the threat is low enough.

#! /bin/sh
out=$(< /dev/stdin)
wget -q -O - --post-data "apikey=YOURKEY&application=APPNAME&event=EVENT&description=${out}" https://nma.usk.bz/publicapi/notify

#! /bin/sh
out=$(< /dev/stdin)
curl -k https://nma.usk.bz/publicapi/notify -F apikey="YOURKEY" -F application="Testing" -F event="test event" -F description="${out}"

Friday, July 8, 2011

Roku searcher

I thought I was done with the Roku but I realized it's a pain to type out a search phrase by running a command for every letter, so here's a way to automate it.

This is geared toward Android phones. For Linux, just change /system/bin/sh to /bin/sh and you might need to change the file on the third line from /sdcard/typer to something else.

What this does is take a phrase from a file and changes the spaces to a "-". They have to change because there's no simple way to recognize the space character as a space. Then it puts a real space between every character so they can be picked out easily, then reads them one at a time and hits the appropriate Roku URL to input that character.

Using Tasker on Android, you can use the Variable Query action to pop up a text box, type "this is a test", write that to a file then execute this script. It will read the phrase, turn it to "T h i s - t e s t", read every character except the spaces, and hits the correct url for that character.

It has to wait between each character or the Roku may not catch every request. Unfortunately, on Android, the minimum wait time is 1 second. On Linux, you can set the sleep command to .3 seconds, trigger this script and watch the characters appear on your TV screen almost as if someone were carefully typing it.

#! /system/bin/sh
ip=YOUR ROKU IP

for i in $(cat /sdcard/typer | sed 's/ /-/g' | sed 's/./& /g')
do
if [ "$i" = "-" ]
then
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_ "; sleep 1
else
wget -q -O - --post-data "" "http://${ip}:8060${click}/keypress/lit_${i}"; sleep 1
fi
echo
done

Thursday, July 7, 2011

Final Roku bash shell script

I played around a little more and cleaned up the Roku remote control script. There's not much else to put in it, but I tweaked how it can be ran and found a few uses for it already.

I don't like the names of some of the options. Who wants to type "roku instantreplay" in a terminal to rewind a few seconds? Not me, but those can all be customized to suit a person's needs. I threw in a few shortcuts. They are:

re = instantreplay
sel = select
del = backspace
wake = backspace (I thought this may be the safest button to use to wake the roku.)

There are three ways to use the script.

1) on the command line with the Roku command you want to run.

roku up
roku home
roku play

2) in "live mode". This is where you type roku live and it waits for you to input commands. This is a bit of a pain to use but it is useful when navigating through menus.

3) in "string mode" with the "str" argument and a bunch of other arguments roku str. I stole string mode from my IP camera script. To use it, just type the commands you want carried out and they will be carried out with a .5 second wait in between.

Example: roku str home right right select down select will go to the home screen, right two channels, select that channel, go down and select again. I find this useful because when my daughter finds a SpongeBob episode that she likes, she wants to watch it 2-3 times. But at the end of every episode, it goes to the next one and waits for you to hit play. To rewatch an episode, you have to move down one spot to "play different episode", hit select, go left to the episode before it, then hit select twice to play it. With my script, I can set up a shortcut to the command roku str down select left select select and replay the episode with a single touch.

Well that's about it, hope someone gets some use out of it.

#! /bin/sh
ip=ROKU IP

mainroku ()
{ case "$input" in

apps)
# will list all installed apps in this format: 12 Netflix
wget -q -O - "http://${ip}:8060/query/apps" | sed -e 's/<app id=\"//g' -e 's#<[^>]*>##g' -e 's/\".*>/ /g';;

go*)
# from the above list, use go plus the number to select channel.
# e.g. "go 12" to go to netflix
wget -q -O - --post-data "" "http://${ip}:8060/launch/${goto#* }"; shift;;

space|sp)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_ "
;;

home|rev|fwd|play|select|left|right|down|up|back|instantreplay|info|backspace|search|enter)
wget -q -O - --post-data "" "http://${ip}:8060/keydown/${input}"
wget -q -O - --post-data "" "http://${ip}:8060/keyup/${input}";;

a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|1|2|3|4|5|6|7|8|9|0)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_${input}";;

## customized
del)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/backspace";;
wake)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/backspace";;
re)
wget -q -O - --post-data "" "http://${ip}:8060/keydown/instantreplay"
wget -q -O - --post-data "" "http://${ip}:8060/keyup/instantreplay";;
sel)
wget -q -O - --post-data "" "http://${ip}:8060/keydown/select"

esac }

if [ "$1" = "live" ]
then
echo "Type your command and hit enter. Type exit to end"
while [ "$input" != "exit" ]
do read input; goto=${input#* }; mainroku
done

elif [ "$1" = "str" ]
then
arg=$(($# - 1))
while [ "$arg" -ne "0" ]
do shift; arg=$(($arg - 1))
goto="$1 $2"
input="$1"
mainroku
sleep .5
done

else input="$1"; goto="$1 $2"; mainroku

fi

Monday, July 4, 2011

bash script to control Roku

This is a very rough draft that I threw together in a few minutes so I'd have something working to play with.

A couple notes:

Assuming you call this script "roku", you can run it two ways, either by sending a command or by running in interactive mode. To send a command, just type the command as an argument. Example, to play a movie, type roku play.

To run in interactive mode, type roku live. In interactive mode, it waits for commands and you can repeat as many as you like until you type exit.

Here is an example of an interactive mode with my comments in italics.

# ./roku live
home goes to main screen
apps lists channels

5127 Roku Spotlight
11 Roku Channel Store
12 Netflix
2016 Movies on Demand
2285 Hulu Plus
28 Pandora
1688 Roku Newscaster
1756 Funny Videos and Pics by Break
2115 SHOUTcast Internet Radio
27 Mediafly
2898 Weather Underground
2963 My Damn Channel
4070 TEDTalks
45 Revision3
4687 Inmoo
6117 SnagFilms
5415 Instant Watch Browser for Netflix

go 12 selects Netflix
search goes to Netflix search screen
l
i
n
u
x these 5 type out "linux"
enter searches for linux
right
select
down
down
select these 5 go to the right one space, select the movie, go down to "add to instant queue and hit select to add it"
exit
#
(and no there aren't any linux movies)

Here are the available commands:

apps- lists all your channels

go x- goes to the number for the channel you want

space - enters a space in search boxes

del - deletes one character in search boxes. same as "backspace" but easier to type

home - goes home

rev/fwd/play/left/right/select/up/down/back/instantreplay/backspace - self explanatory.

info - seems to only work on home screen. allows you to change channel position, see rating, description and remove channel

search - goes directly to search screens if the channel supports it. works in Netflix

enter - when in a search box, this carries out the search. may have a use in other text boxes.

a-z and 0-9 - self explanatory.

And here's the script.

#! /bin/sh 
## put your Roku IP address below ##
ip=

infunc ()
{
read input
case "$input" in

apps)
wget -q -O - "http://${ip}:8060/query/apps" | sed -e 's/<app id=\"//g' -e 's#<[^>]*>##g' -e 's/\".*>/ /g'
;;

go*)
wget -q -O - --post-data "" "http://${ip}:8060/launch/${input#* }"
;;

space)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_ "
;;

del)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/backspace"
;;

home|rev|fwd|play|select|left|right|down|up|back|instantreplay|info|backspace|search|enter)
wget -q -O - --post-data "" "http://${ip}:8060/keydown/${input}"
wget -q -O - --post-data "" "http://${ip}:8060/keyup/${input}"
;;

a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|1|2|3|4|5|6|7|8|9|0)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_${input}"
;;
esac
if [ "$input" != "exit" ]; then infunc; fi
}

if [ "$1" = "live" ]; then infunc; fi


case "$1" in

apps)
wget -q -O - "http://${ip}:8060/query/apps" | sed -e 's/<app id=\"//g' -e 's#<[^>]*>##g' -e 's/\".*>/ /g'
;;

go)
wget -q -O - --post-data "" "http://${ip}:8060/launch/${2}"
;;

space)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_ "
;;

del)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/backspace"
;;

home|rev|fwd|play|select|left|right|down|up|back|instantreplay|info|backspace|search|enter)
wget -q -O - --post-data "" "http://${ip}:8060/keydown/${1}"
wget -q -O - --post-data "" "http://${ip}:8060/keyup/${1}"
;;

a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|1|2|3|4|5|6|7|8|9|0)
wget -q -O - --post-data "" "http://${ip}:8060/keypress/lit_${1}"
;;

esac

Control Roku from command line

I got a Roku to play Netflix Instant on my TV (as well as other channels available through Roku). It connects to your wifi or ethernet and streams video through a wire to your TV and is controlled with a remote control. The Roku has two output ports, one for RCA cables and one for HDMI cables. I have the HDMI going to the TV in the living room and RCA cables going to my bedroom TV so I can also watch the Roku in there. But, of course, the remote control doesn't work from my bedroom.

Luckily, the Roku can also be controlled over your home network. There is a Roku remote control app available for Android called RoMote which works great, except you have to tell it to connect and it loses the connection when you close the app. If you only need to push one button, like Pause, it's a bit of a hassle because you have to open the app, click connect, then tap Pause and close the app.

There is an SDK available that allows developers to create their own apps, which is obviously how the RoMote developer made his. This is an example of what the SDK uses for the general format for keypresses. This example uses the Home button and assumes the Roku IP is 192.168.1.6.

echo -e 'POST /keypress/Home/1.1\r\n\r\n' | ncat 192.168.1.6 8060

Yuck. Luckily again, we can make that a little nicer looking by using cURL or wget to post data.

curl -d "" "http://192.168.1.6:8060/keypress/Home"

wget --post-data "" "http://192.168.1.6:8060/keypress/play"

The Roku only seems to work with the HTTP POST method. The -d option tells cURL to post http data and obviously the "--post-data" option does the same for wget. The data is supposed to be between the first quotation marks and as you see, mine are empty, so it's posting, but it's posting nothing. The important part is the url that it posts to, in this case /keypress/Home. When the Roku detects a post to that url, it acts as if the Home key on the remote control has been pressed.

Here is a list of the available controls:

Home
Rev
Fwd
Play
Select
Left
Right
Down
Up
Back
InstantReplay
Info
Backspace
Search
Enter
Lit_

Lit_ is special, you enter a letter with Lit_x. For example, to search for movies containing "foo", you'd hit the following 5 urls in order:

Search
Lit_F
Lit_O
Lit_O
Enter

The /query/apps URL will give you a list of the apps installed on the Roku. Apps are basically channels. There is a Netflix app, WeatherChannel app, etc. The data comes back in xml format.
# curl http://192.168.1.6:8060/query/apps                              
<apps>
<app id="5127" version="1.0.10">Roku Spotlight</app>
<app id="11" version="2.1.22">Roku Channel Store</app>
<app id="12" version="2.3.20">Netflix</app>
<app id="2016" version="2.0.37">Movies on Demand</app>
<app id="2285" version="1.9.1">Hulu Plus</app>
<app id="28" version="1.0.24">Pandora</app>
<app id="1688" version="1.5.10">Roku Newscaster</app>
<app id="1756" version="1.5.5">Funny Videos and Pics by Break</app>
<app id="2115" version="1.4.1">SHOUTcast Internet Radio</app>
<app id="27" version="1.1.110207">Mediafly</app>
<app id="2898" version="0.0.0">Weather Underground</app>
<app id="2963" version="1.0.0">My Damn Channel</app>
<app id="4070" version="1.5.1306292789">TEDTalks</app>
<app id="45" version="1.5.0">Revision3</app>
<app id="4687" version="1.0.0">Inmoo </app>
<app id="6493" version="1.0.1">Sunlight Foundation White House Video Stream</app>
<app id="1980" version="1.1.100907">Vimeo</app>
<app id="2091" version="1.2.1">Warriors of War</app>
</apps>
#

If you want to watch a channel, just hit this url containing the numerical ID. For example, if you want to check the weather:

/launch/11?contentID=2898

And using the numerical ID, you can view that channel's icon using this url: /query/icon/2898.

That's pretty much all there is to imitating the Roku remote control. I'll probably be putting this all into a script and posting it later when I have more time. Being able to control it this way allows you to script your player. For example, Netflix has entire seasons of TV shows available but doesn't have a "play all" option, so you could use this to watch one, wait 23 minutes, watch another etc then you could have Weather Undergroud start playing at the time you wake up.

This can also be controlled through your Android phone. cURL isn't available on Android, but see wget is, and see my earlier post about using Tasker to post HTTP data.

Sunday, May 22, 2011

No internet

Ugh, if you move into a newly constructed house, make sure to sort everything early. I ended up moving before the cable was connected, but they were scheduled to do it Saturday. When the tech got everything wired up, he found that my side if the street wasn't tapped into the cable on the main street yet, so it's going to be at least another week until I get cable/internet. I guess everyone else on my side of the street is using satellite or something.

I have at least been able to get a little home automation done. I put rope lights above the kitchen cabinets. When watching a movie in the living room, they provide a very nice faint glow in the background. I can get up and get a drink without turning on any other lights.

I'm temporarily using X10 lamp modules to control them and have a cron job on the computer turn them on at 7am so I have a gentle glow to light my way when I wake up and stumble into the kitchen. I'll probably put in X10 outlets all throughout the house later and I already have several X10 switches that I need to wire in.

Not much else to report. I just wanted to check in. With no internet, I haven't felt like doing anything cool tech-wise. It ain't cool if you can't do it remotely.


Monday, May 9, 2011

Yay, new house.

I closed on the house today and it's been a frustrating ride. The builder had to fix a few things and on the second inspection... nothing had been fixed. Last week, they were working on it and no thanks to a lender that couldn't be bothered to do anything, I had to coordinate with the title company myself to get the closing done, and in the process forgot to do a final inspection.

Oh well, I'm sure they took care of it, right? Nope, I walked in to my new home to find that they still weren't done. But I got the keys and they're going to finish tomorrow and I will move this weekend.

With a brand new house and brand new furniture, I think it's time for some brand new computing power. I'm thinking a couple wifi repeaters, a server in the closet to run X10, storage, maybe even media and an Android tablet as a remote control for everything.

Maybe.

I'll soon be moved and hopefully have something worth blogging.

Monday, April 11, 2011

Light posting

Well, that's not new, I'm not a very prolific blogger, but posting may (or may not) be light for the next month. I'm buying a new house- literally, it just got built- and will be going crazy trying to get everything done and get moved. I'm not sure when I will move, I told someone that I will probably follow the internet. Once the internet gets turned off here and on there, I'm moving that day!

On the plus side, I will finally have an excuse to go nuts with X10. The house has tray ceilings in the living room and master bedroom, so I'm planning to put in some lighting like this which just begs to be controlled with X10 and a dimmer.



Then there's the rest of the house, I'm just itching to go X10 crazy on it.

Anyway, if I don't post much for the next month, don't get alarmed and call Dog The Bounty Hunter to look for me. I'll be around.

Tuesday, April 5, 2011

Get current url from Android browser

I've been using an app called Wave Launcher, which allows you to swipe a certain area of the screen to pop up a launch bar. The launch bar contains 5 icons which you can set up to open an app or shortcut. With Folder Organizer, you can have it open a folder of apps, or, even cooler, a folder full of Tasker tasks.

I wanted to create a Tasker task to open my computer's browser to the same url that my phone's browser is on. I can do this by copying the url and running a task to share it, but that's too much work. After much digging, I found a way to extract the current url from the browser database.
sqlite3 /data/data/com.android.browser/databases/browser.db "SELECT * FROM bookmarks;" | tr '|' '\n' | grep http | tail -n1

If you go to cnn.com on the phone and run that command, the output is http://m.cnn.com/.

Using that, I can make a short script to make it open on my home computer via ssh:

#! /system/bin/sh
url=$(sqlite3 /data/data/com.android.browser/databases/browser.db "SELECT * FROM bookmarks;" | tr '|' '\n' | grep http | tail -n1)
ssh -i /PATH/TO/SSHKEY USER@IP "firefox $url"

If I'm browsing a page on the phone and want to read it on the computer instead, I can swipe Wave Launcher and select the task that runs this command. This will grab the last url visited, so it doesn't matter if the browser is open or closed.

Saturday, April 2, 2011

shell launcher for sl4a scripts

Scripting Layer for Android, or SL4A is an app which allows you to run scripts such as perl and python on your phone. The cool thing about them is that they have full access to Android API calls, unlike the Android command line. But sl4a scripts can be invoked from the command line and here's a script to do it.

Everything from "am" to the end needs to be on one line, but it's too long to post it that way here and I've always found the typical way of splitting lines on the web with a backslash confuses people, so just make sure "am...}" goes on a single line or copy it from the QR code below.

To run it, just execute the script with the name of an sl4a script as an argument. e.g., if you name the script slsh you run "slsh test.py"

#! /system/bin/sh
[ -z "$1" ] && exec echo "please specify the name of a script to run"
am start -a com.googlecode.android_scripting.action.LAUNCH_BACKGROUND_SCRIPT
-n com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher
-e com.googlecode.android_scripting.extra.SCRIPT_PATH /sdcard/sl4a/scripts/${1}

This could give you the ability to do virtually anything on the phone through the command line by invoking sl4a scripts. sl4a would do the hard work, of course, but this gives you a lower level access to it. You could, for example, probably use it to easily ssh into the phone from the computer and send a text message or get the GPS location.

Copy "slsh" to your phone's clipboard with this QR code:

Friday, April 1, 2011

New Tasker Forum

Pent has created a new discussion group called Tasker Pro in response to this thread where people lamented the lack of a good place where people could put their heads together and come up with cool Tasker solutions.

Wednesday, March 30, 2011

wget Android port

I can't take credit for it, but someone ported the real GNU wget utility to Android. I found this many months ago and have kept it on my phone. The wget that came with busybox worked great for a while, but after my upgrade to Cyanogen 7 a couple of weeks ago, I noticed several of my Tasker tasks were failing. I finally figured out that it was due to the busybox wget located in /system/xbin/wget. I deleted it and dropped this into /system/bin and everything started working again.

I uploaded it here in case anyone wants it (and so I don't lose it myself.)

Thanks to whoever originally compiled it for Android!

Sunday, March 13, 2011

ssh hiccupped

I will never understand some things.

Last night, I sat down to watch a movie and dimmed the lights using ssh on my phone (using a Zoom widget to run the ssh command to my PC and trigger heyu controlling home automation, it's all here on the blog somewhere). After the movie, I went to brighten the lights and found that it didn't work. After much investigation, I found that ssh was failing to connect to my PC. No matter what I tried, ssh failed with this error:

no address associated with hostname

I recently installed an app which created network sockets in order to watch network traffic, so I thought maybe that screwed something up. I had no idea how to fix it, and it was time for an update anyway, so I wiped the phone and installed the latest Cyanogenmod today (7RC2). After getting everything installed and set up, I dropped to a terminal and tried to ssh in to the PC and got:

no address associated with hostname

What the..? Ping and everything else worked, so it didn't seem to be a DNS issue. Maybe Google shipped out an Android OTA update that changed the network stack somehow?

I finally found a fix by adding my PC's IP address to /etc/hosts and giving it a name:

xx.xxx.xx.xx home

Then ssh user@home worked! I keep the home IP address stored in a file so it was easy to change all of my ssh commands by changing the ip address in that file to "home", and it's worked all day with no problems.

Later tonight, I was trying to set up a new connection and accidentally typed ssh user@xx.xxx.xx.xx and, after changing absolutely nothing, it works again!

Well, the two lessons for today are that if ssh gives you that error, try hardcoding the ip address in /etc/hosts and connecting to it's hostname instead of the ip directly and when it comes to computing, just accept the fact that sometimes, things will make absolutely no sense whatsoever.

Thursday, March 10, 2011

RemoteDroid

RemoteDroid is a great little app that turns your Android phone into a mouse/keyboard to use with your computer. I mainly use it as a remote control for mplayer because mplayer uses keyboard shortcuts (which can be customized by editing ~/.mplayer/input.conf). I use the command line version, the GUI version is probably the same, but I've never used it so I can't say for sure.

The two work perfectly together. I can lay in bed and watch a movie on the computer at my desk and control it with my phone by tapping the keyboard in RemoteDroid. The only downside is that the server needed on the computer automatically opens a small screen. If you want to start the RemoteDroid server at boot, you have to live with that screen always being open. But there is a solution with KDE.

I'm sure something similar can be done with Gnome, but I've been using KDE for 10 years so I'm pretty much stuck with it and will probably still be using it when I'm an old ornery, cantankerous man (as opposed to the young ornery, cantankerous man I am today).

With KDE, When the RemoteDroid window comes up, right click on it and click "Configure Window Bahavior". This will bring up the KDE configuration utility.

Click Window Specific, then click "new" and click "Detect Window Properties". Your cursor will change to a crosshair. Click on the RemoteDroid window and it should automatically fill out the information for the RemoteDroid window.

Now go to the Geometry tab and click "minimized" then select the Preferences tab and select "Skip taskbar". Now when the window opens, it will be effectively invisible. It will be minimized so you won't see it on the screen, and it will not appear in the taskbar so there's no way for it to become unminimized.

Now, to run RemoteDroid when KDE starts, open a terminal and go to your kde autostart folder:

cd ~/.kde/Autostart

make a new script named startRemoteDroid.sh (or whatever you want to call it):

touch startRemoteDroid.sh

put this in the script, changing /PATH/TO to the path where RemoteDroid is on your system:

#! /bin/sh
java -jar /PATH/TO/RemoteDroidServer/RemoteDroidServer.jar &


make it executable:

chmod 755 startRemoteDroid.sh

and you're done. RemoteDroid will automatically start when KDE starts, and it will be invisible.

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

Followers