Android and Linux

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.

Followers