Sunday, July 10, 2016

Amateur Radio - callsign lookup via voice command

I've been thinking about writing this Tasker + Autovoice project for a while. I finally got a little time to work out the details. This profile is a voice command to look up the station operator's name when the callsign is provided.
(If you haven't heard of Tasker it is a smartphone app for automating tasks). The XML api service on QRZ.com allows simple database queries. The XML file I posted needs edited with your callsign and password for the text mycallsign and mypassword. Just put your QRZ credentials in and then import the project into Tasker. You can see how I used the Variable Splitter function to parse the returned text from the HTTP GET query. (I'll probably add the feature for reporting the station's grid square in the future.) My internet is a little slow, so it takes a moment for the task to run and speak the results to me.Here's the improved XML code.  You will need Tasker and Autovoice installed on your smartphone before importing this script.
Search for mycallsign and mypassword (on line 121 of the script) and replace them with your login credentials from QRZ.com.
When the script is run by speaking "OK Google" then say
"qrz callsign" with the callsign that you want to look up... like W1AW for instance.

"OK GOOGLE, QRZ W1AW"

<TaskerData sr="" dvi="1" tv="4.8u5m">
<Profile sr="prof86" ve="2">
<cdate>1468014494157</cdate>
<edate>1468073555161</edate>
<id>86</id>
<mid0>87</mid0>
<mid1>88</mid1>
<State sr="con0" ve="2">
<code>1402352892</code>
<Bundle sr="arg0">
<Vals sr="val">
<Contains>false</Contains>
<Contains-type>java.lang.Boolean</Contains-type>
<DisableCommand>&lt;null&gt;</DisableCommand>
<DisableCommand-type>java.lang.String</DisableCommand-type>
<DisableCommandExact>false</DisableCommandExact>
<DisableCommandExact-type>java.lang.Boolean</DisableCommandExact-type>
<DisableCommandRegex>false</DisableCommandRegex>
<DisableCommandRegex-type>java.lang.Boolean</DisableCommandRegex-type>
<LastCommandIdInvert>false</LastCommandIdInvert>
<LastCommandIdInvert-type>java.lang.Boolean</LastCommandIdInvert-type>
<LastCommandIdRegex>false</LastCommandIdRegex>
<LastCommandIdRegex-type>java.lang.Boolean</LastCommandIdRegex-type>
<NotCancelSearchGoogleNow>false</NotCancelSearchGoogleNow>
<NotCancelSearchGoogleNow-type>java.lang.Boolean</NotCancelSearchGoogleNow-type>
<NotOnContinuous>false</NotOnContinuous>
<NotOnContinuous-type>java.lang.Boolean</NotOnContinuous-type>
<NotOnNormal>false</NotOnNormal>
<NotOnNormal-type>java.lang.Boolean</NotOnNormal-type>
<Precision>&lt;null&gt;</Precision>
<Precision-type>java.lang.String</Precision-type>
<ProfileName>&lt;null&gt;</ProfileName>
<ProfileName-type>java.lang.String</ProfileName-type>
<Source>&lt;null&gt;</Source>
<Source-type>java.lang.String</Source-type>
<Substitutions>&lt;null&gt;</Substitutions>
<Substitutions-type>java.lang.String</Substitutions-type>
<TriggerWord>&lt;null&gt;</TriggerWord>
<TriggerWord-type>java.lang.String</TriggerWord-type>
<TriggerWordExact>false</TriggerWordExact>
<TriggerWordExact-type>java.lang.Boolean</TriggerWordExact-type>
<TriggerWordRegex>false</TriggerWordRegex>
<TriggerWordRegex-type>java.lang.Boolean</TriggerWordRegex-type>
<VariableNames>&lt;null&gt;</VariableNames>
<VariableNames-type>java.lang.String</VariableNames-type>
<VariableValues>&lt;null&gt;</VariableValues>
<VariableValues-type>java.lang.String</VariableValues-type>
<com.twofortyfouram.locale.intent.extra.BLURB>Event Behaviour: true
Command: "qrz (?&lt;callsign&gt;.+) (regex)"
Last Cmd Id Regex: false
Last Cmd Id Invert: false
Not on Normal: false
Not on Continuous: false
Contains All: false
Use Regex Replacements: false
Do Google Now Search: false</com.twofortyfouram.locale.intent.extra.BLURB>
<com.twofortyfouram.locale.intent.extra.BLURB-type>java.lang.String</com.twofortyfouram.locale.intent.extra.BLURB-type>
<configcommand>qrz (?&lt;callsign&gt;.+)</configcommand>
<configcommand-type>java.lang.String</configcommand-type>
<configcommandid>&lt;null&gt;</configcommandid>
<configcommandid-type>java.lang.String</configcommandid-type>
<configcommandinvert>false</configcommandinvert>
<configcommandinvert-type>java.lang.Boolean</configcommandinvert-type>
<configexactsub>false</configexactsub>
<configexactsub-type>java.lang.Boolean</configexactsub-type>
<configinstant>true</configinstant>
<configinstant-type>java.lang.Boolean</configinstant-type>
<configlastcommand>&lt;null&gt;</configlastcommand>
<configlastcommand-type>java.lang.String</configlastcommand-type>
<configregexsub>true</configregexsub>
<configregexsub-type>java.lang.Boolean</configregexsub-type>
<net.dinglisch.android.tasker.RELEVANT_VARIABLES>&lt;StringArray sr=""&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;%avcomm
First recognized Command
&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES1&gt;%avcommnofilter
First Command Without Filter
&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES1&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES2&gt;%avcomms()
All recognized commands
&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES2&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES3&gt;%avcommsnofilter()
All recognized commands without filter
&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES3&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES4&gt;%avsource
Source of the Voice Command
Can be normal, continuous, test or googlenow&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES4&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES5&gt;%avword()
Word Array
&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES5&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES6&gt;%callsign
First "callsign"
First match for group "callsign"&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES6&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES7&gt;%regexgroups()
Regex Groups
Regex Groups&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES7&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES8&gt;%regexmatch
Regex Match
Regex Match&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES8&gt;&lt;/StringArray&gt;</net.dinglisch.android.tasker.RELEVANT_VARIABLES>
<net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>[Ljava.lang.String;</net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>
<net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS>configcommand plugininstanceid plugintypeid </net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS>
<net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS-type>java.lang.String</net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS-type>
<net.dinglisch.android.tasker.subbundled>true</net.dinglisch.android.tasker.subbundled>
<net.dinglisch.android.tasker.subbundled-type>java.lang.Boolean</net.dinglisch.android.tasker.subbundled-type>
<plugininstanceid>bf5bbf3d-9859-41b4-bc61-8e2d6f9e2a92</plugininstanceid>
<plugininstanceid-type>java.lang.String</plugininstanceid-type>
<plugintypeid>com.joaomgcd.autovoice.intent.IntentReceiveVoice</plugintypeid>
<plugintypeid-type>java.lang.String</plugintypeid-type>
</Vals>
</Bundle>
<Str sr="arg1" ve="3">com.joaomgcd.autovoice</Str>
<Str sr="arg2" ve="3">com.joaomgcd.autovoice.activity.ActivityConfigReceiveVoice</Str>
</State>
</Profile>
<Project sr="proj0" ve="2">
<cdate>1467978939203</cdate>
<name>QRZ Look</name>
<pids>86</pids>
<tids>88,87</tids>
</Project>
<Task sr="task87">
<cdate>1467979303743</cdate>
<edate>1468073445011</edate>
<id>87</id>
<nme>Qrz Db Query Call</nme>
<pri>100</pri>
<Action sr="act0" ve="7">
<code>118</code>
<Str sr="arg0" ve="3">online.qrz.com</Str>
<Str sr="arg1" ve="3">/bin/xml?username=mycallsign;password=mypassword</Str>
<Str sr="arg2" ve="3"/>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Int sr="arg5" val="20"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3"/>
<Int sr="arg8" val="0"/>
</Action>
<Action sr="act1" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%qrzgetkey</Str>
<Str sr="arg1" ve="3">%HTTPD</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act10" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">&lt;name&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act11" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat2</Str>
<Str sr="arg1" ve="3">&lt;/name&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act12" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%lname</Str>
<Str sr="arg1" ve="3">%qrzcallsigndat21</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act13" ve="7">
<code>559</code>
<Str sr="arg0" ve="3">%callsign is</Str>
<Str sr="arg1" ve="3">default:default</Str>
<Int sr="arg2" val="3"/>
<Int sr="arg3" val="5"/>
<Int sr="arg4" val="5"/>
<Int sr="arg5" val="1"/>
<Int sr="arg6" val="0"/>
<Int sr="arg7" val="0"/>
</Action>
<Action sr="act14" ve="7">
<code>559</code>
<Str sr="arg0" ve="3">%fname %lname</Str>
<Str sr="arg1" ve="3">default:default</Str>
<Int sr="arg2" val="3"/>
<Int sr="arg3" val="5"/>
<Int sr="arg4" val="5"/>
<Int sr="arg5" val="1"/>
<Int sr="arg6" val="0"/>
<Int sr="arg7" val="0"/>
</Action>
<Action sr="act15" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">%callsign is %fname %lname</Str>
<Int sr="arg1" val="0"/>
</Action>
<Action sr="act2" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzgetkey</Str>
<Str sr="arg1" ve="3">&lt;Key&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act3" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzgetkey2</Str>
<Str sr="arg1" ve="3">&lt;/Key&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act4" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%qrzkey</Str>
<Str sr="arg1" ve="3">%qrzgetkey21</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act5" ve="7">
<code>118</code>
<Str sr="arg0" ve="3">xmldata.qrz.com</Str>
<Str sr="arg1" ve="3">/xml/current/?s=%qrzkey;callsign=%callsign</Str>
<Str sr="arg2" ve="3"/>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Int sr="arg5" val="20"/>
<Str sr="arg6" ve="3"/>
<Str sr="arg7" ve="3"/>
<Int sr="arg8" val="0"/>
</Action>
<Action sr="act6" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">%HTTPD</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act7" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">&lt;fname&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act8" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat2</Str>
<Str sr="arg1" ve="3">&lt;/fname&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act9" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%fname</Str>
<Str sr="arg1" ve="3">%qrzcallsigndat21</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Img sr="icn" ve="2">
<cls>com.apklabs.android.calllog.CallLog</cls>
<pkg>com.apklabs.android.calllog</pkg>
</Img>
</Task>
<Task sr="task88">
<cdate>1467979303743</cdate>
<edate>1468073330847</edate>
<id>88</id>
<nme>Qrz Db Query Qth</nme>
<pri>100</pri>
<Action sr="act0" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">%HTTPD</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act1" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">&lt;addr2&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act10" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%state</Str>
<Str sr="arg1" ve="3">%qrzcallsigndat21</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act11" ve="7">
<code>559</code>
<Str sr="arg0" ve="3">State of %state</Str>
<Str sr="arg1" ve="3">default:default</Str>
<Int sr="arg2" val="3"/>
<Int sr="arg3" val="5"/>
<Int sr="arg4" val="5"/>
<Int sr="arg5" val="1"/>
<Int sr="arg6" val="0"/>
<Int sr="arg7" val="0"/>
</Action>
<Action sr="act2" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat2</Str>
<Str sr="arg1" ve="3">&lt;/addr2&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act3" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%city</Str>
<Str sr="arg1" ve="3">%qrzcallsigndat21</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act4" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">&lt;country&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act5" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat2</Str>
<Str sr="arg1" ve="3">&lt;/country&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act6" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%country</Str>
<Str sr="arg1" ve="3">%qrzcallsigndat21</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act7" ve="7">
<code>559</code>
<Str sr="arg0" ve="3">from %city %country</Str>
<Str sr="arg1" ve="3">default:default</Str>
<Int sr="arg2" val="3"/>
<Int sr="arg3" val="5"/>
<Int sr="arg4" val="5"/>
<Int sr="arg5" val="1"/>
<Int sr="arg6" val="0"/>
<Int sr="arg7" val="0"/>
</Action>
<Action sr="act8" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat</Str>
<Str sr="arg1" ve="3">&lt;state&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act9" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%qrzcallsigndat2</Str>
<Str sr="arg1" ve="3">&lt;/state&gt;</Str>
<Int sr="arg2" val="0"/>
</Action>
<Img sr="icn" ve="2">
<cls>com.apklabs.android.calllog.CallLog</cls>
<pkg>com.apklabs.android.calllog</pkg>
</Img>
</Task>
</TaskerData>