AppleScript to set EZX10RF parameters

Posted on
Sun Jan 27, 2008 12:44 pm
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

AppleScript to set EZX10RF parameters

By studying the raw Insteon codes generated by the Simplehomenet Utility running under Windows, I thought I'd write an AppleScript to reproduce this functionality in Indigo. Here's my first crack. Running this code as-is will turn off X10 reception for all units with house code B.

I have zero experience with AppleScript, let alone writing scripts for Indigo, so I'm hoping the experts on this forum can help. In particular, how do I obtain the ack code sent by an Insteon device? How do you specify hex values in AppleScript -- the 0x prefix doesn't work and I can't find any good AppleScript documentation online.

After fine-tuning this code, my next step will be to set the X10-to-Insteon translation table.

George

Code: Select all
--First crack at a script to set the X10 filter on the EZX10RF module
--by George Musser
--27 Jan 08

set addressEZ to "0C.AF.7D" -- Insteon address of EZX10RF module

tell application "IndigoServer"
   
   --set high byte of memory address for subsequent commands
   send insteon raw cmd1 40 cmd2 0 to address addressEZ
   
   --set the registers
   --cycle through the 2-byte registers associated with each X10 house code
   repeat with memoryLocation from 6 to 7 -- as a test case, use house code B
      
      --specify the low byte of the address
      send insteon raw cmd1 43 cmd2 memoryLocation to address addressEZ
      
      --here we should look for an ack (in this case, 0x2B followed by the current register value) but I don't know how to do that; the Indigo Event Log lists the ack code
      
      --poke in a 0 value, which turns off filtering for all the unit codes
      --to enable a unit code, poke a 1 bit at the bit corresponding to the unit
      --e.g. 4 corresponds to unit code 3
      send insteon raw cmd1 41 cmd2 0 to address addressEZ
      
      --in this case, the ack should be the poked value
      
   end repeat
   
end tell

Posted on
Sun Jan 27, 2008 3:48 pm
matt (support) offline
Site Admin
User avatar
Posts: 19173
Joined: Jan 27, 2003
Location: Texas

Re: AppleScript to set EZX10RF parameters

Hi George,

There isn't currently a way to get the ACK value back in AppleScript. Unfortunately, this is more complicated than it might seem, mainly because AppleScript has to be executed in the process's main thread but Indigo sends and receives all INSTEON commands in a dedicated interface thread.

That said, there are internal routines Indigo has which makes poking data into a remote INSTEON module easy, although it can be dangerous since it can overwrite links and other settings. I'll look into providing a new AppleScript verb to allow for that remote poking.

Regards,
Matt

Posted on
Sun Jan 27, 2008 4:19 pm
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

(No subject)

Is there a way for AppleScript to read the Indigo Event Log (which *does* contain the ack code)?

Have you tested my little script to see whether it works? Do you have any coding tips? I don't even know if I'm following good AppleScript practice in variable naming, for example.

George

Posted on
Sun Jan 27, 2008 4:29 pm
matt (support) offline
Site Admin
User avatar
Posts: 19173
Joined: Jan 27, 2003
Location: Texas

(No subject)

gmusser wrote:
Is there a way for AppleScript to read the Indigo Event Log (which *does* contain the ack code)?

Maybe. You can use the verb build event log list line count num_lines_you_want to return the last few Event Log lines. But you'll need to add a delay because all of your send insteon raw commands will be executed immediately and put into the outbound PowerLinc queue. You would have to delay and loop to watch for when the Event Log line you want is written. This may not be that reliable since the delay can vary based on other traffic on the power line, or other commands pending in the outgoing PowerLinc queue.

gmusser wrote:
Have you tested my little script to see whether it works? Do you have any coding tips? I don't even know if I'm following good AppleScript practice in variable naming, for example.

I haven't tested it, but it looks good to me. I think you only need to do the 43 (hex 2B) peek command the first time through the loop (or just do it outside the loop). Every time you execute the Poke command it automatically increments the PARPTR by 1.

Matt

Posted on
Mon Jan 28, 2008 10:37 pm
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

(No subject)

Here's v2 of the script. I've tried to make it more transparent. But I've still commented out two lines to prevent it from actually working -- I recommend that someone else test it first!
George

Code: Select all
--Second crack at a script to set the X10 filter on the EZX10RF module
--by George Musser
--28 Jan 08

--Running the script clears the X10 filter table and then sets the codes listed in the global array.
--It does *not* create new device links or X10-to-Insteon mappings. To do that, I first need to
--figure out how to do link management.

--The routine has some error-checking, but doesn't work well if there's noise on the line.

--To save you grief, I've commented out two lines that actually do the dirty work, so that you
--can test the script for yourself before setting it loose on your EZX10RF.

--EZX10RF memory map and Insteon command set is available at http://www.simplehomenet.com/Downloads/EZX10RF%20Command%20Set.pdf

property addressEZ : "0C.AF.7D" -- Insteon address of EZX10RF module

--Here's the list of X10 address to allow through.

property X10list : {"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "E4"}

main()

on main()
   --comment this back in when you're ready!
   --clearFlags()
   repeat with currentX10address in X10list
      setFlag(currentX10address, true)
   end repeat
end main

on clearFlags()
   tell application "IndigoServer"
      
      --set starting memory address for subsequent commands
      send insteon raw cmd1 40 cmd2 0 to address addressEZ -- high byte
      send insteon raw cmd1 43 cmd2 6 to address addressEZ -- low byte (starting with house code B for now)
      
      --cycle through the 2-byte registers associated with each X10 house code and clear them
      repeat 32 times
         
         --poke in a 0 value, which turns off filtering for all the unit codes         
         set ack to my getAck(41, 0, addressEZ)
         
         --make sure it cleared properly
         if ack is not 0 then
            log "Unable to verify command"
            exit repeat
         end if
         
      end repeat
      
   end tell
end clearFlags


--here's a kludge to get the ACK code after sending raw Insteon commands
--this requires complete quiet on the power line

on getAck(byte1, byte2, addr)
   tell application "IndigoServer"
      
      --the ulterior purpose of this log command is to ensure that a time stamp doesn't contaminate
      --the ACK line
      log "Ready to send raw insteon"
      
      --here we actually send the command
      send insteon raw cmd1 byte1 cmd2 byte2 to address addr
      
      try
         set ackDec to -1
         
         --wait for the ack to come through
         repeat 8 times
            
            --grab the most recent line of the log
            --unfortunately, the date and time sometimes get mixed in
            set latestLogLine to build event log list line count 1
            
            --is it what we're looking for?
            --is there a better way of doing this?
            if second word of latestLogLine is "INSTEON" then
               if fourth word of latestLogLine is "raw" then
                  if my Hex2Dec(text 54 thru 55 of latestLogLine) is byte1 then
                     if my Hex2Dec(text 57 thru 58 of latestLogLine) is byte2 then
                        set ackDec to my Hex2Dec(last word of latestLogLine)
                        exit repeat
                     end if
                  end if
               end if
            end if
            delay 0.25
         end repeat
         
         if ackDec < 0 or ackDec > 255 then
            return -1
         else
            return ackDec
         end if
      on error
         return -1
      end try
   end tell
end getAck


--set a specific X10 flag on or off
--to enable a unit code, poke a 1 bit at the bit corresponding to the unit
--e.g. 4 corresponds to unit code 3

on setFlag(X10address, newFlag)
   tell application "IndigoServer"
      
      --first, check the arguments
      if class of X10address is not string or class of newFlag is not boolean then return -1
      
      --second, parse the X10 address
      set houseASCIICode to text 1 of X10address
      set houseCode to offset of houseASCIICode in "ABCDEFGHIJKLMNOP"
      if length of X10address is 1 then
         return -1
      else if length of X10address is 2 then
         set unitCode to text 2 of X10address as number
      else
         set unitCode to text 2 thru 3 of X10address as number
      end if
      
      --third, do some error-checking
      if houseCode > 15 or unitCode > 15 then return -1
      
      --fourth, convert to an offset within the EZX10RF table
      set memoryIndex to 2 + houseCode * 2
      if unitCode ≤ 8 then
         set unitCode to unitCode - 1
      else
         set memoryIndex to memoryIndex + 1
         set unitCode to unitCode - 9
      end if
      
      --fifth, read the existing byte
      set reflectedAddress to my getAck(40, 0, addressEZ) -- address MSB
      if reflectedAddress is not 0 then return -1
      set currentByte to my getAck(43, memoryIndex, addressEZ) -- address LSB
      if currentByte is -1 then return -1
      
      --sixth, mask in the new flag value
      set mask to (2 ^ unitCode) as integer
      if newFlag then
         set newByte to my BitwiseOr(currentByte, mask)
      else
         set newByte to my BitWiseAnd(currentByte, my BitwiseNot(mask))
      end if
      
      --seventh, write the byte
      --when you're ready, comment this in and the debug line out
      --send insteon raw cmd1 41 cmd2 newByte to address addressEZ
      
      tell application "Script Editor"
         display dialog "address " & memoryIndex & ", old value " & currentByte & ", new value " & newByte
      end tell
   end tell
end setFlag


--can someone tell me why AppleScript doesn't already have the following operators?
on BitwiseOr(i, j)
   return (do shell script "perl -e 'printf(\"%d\"," & i & "|" & j & ")'") as number
end BitwiseOr

on BitWiseAnd(i, j)
   return (do shell script "perl -e 'printf(\"%d\"," & i & "&" & j & ")'") as number
end BitWiseAnd

on BitwiseNot(i)
   return 256 + (do shell script "perl -e 'printf(\"%d\",~" & i & ")'") as number
end BitwiseNot

--AppleScript stupidly doesn't have native functions for handling hexadecimal, but here's an elegant workaround from http://bbs.applescript.net/viewtopic.php?id=19442
on Hex2Dec(s)
   return (do shell script "perl -e 'printf(hex(\"" & s & "\"))'") as number
end Hex2Dec

Posted on
Tue Jan 29, 2008 7:10 pm
matt (support) offline
Site Admin
User avatar
Posts: 19173
Joined: Jan 27, 2003
Location: Texas

(No subject)

Hi George,

Looks good to me! I don't have the EZX10RF myself, but hopefully someone else will give you some feedback. The code looks nice -- it has comments even. ;-)

Thanks for sharing.

Regards,
Matt

Posted on
Tue Jan 29, 2008 8:31 pm
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

(No subject)

Hi Matt,
How do I virtually press the PowerLinc set button from AppleScript? The EZX10RF has a command to enter linking mode, but I need to know what to do on the PowerLinc side to complete it.
George

Posted on
Tue Jan 29, 2008 11:14 pm
bob offline
User avatar
Posts: 500
Joined: Jun 14, 2006

(No subject)

Hello George - I was about to give a go of your script but it won't compile - I got the following syntax error "A “>” can't go after this number."

regards,

bob

Posted on
Wed Jan 30, 2008 7:14 am
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

(No subject)

Ah, when I pasted the code into the message, the spaces before and after all the greater-than and less-than signs were lost. I tried to paste it into this message but the same thing happened. I don't see a way to upload a file to the forum. Matt, what should I do?
George

Posted on
Wed Jan 30, 2008 8:03 am
matt (support) offline
Site Admin
User avatar
Posts: 19173
Joined: Jan 27, 2003
Location: Texas

(No subject)

I just checked the Disable HTML in this post checkbox for that message. It should work now.

Regards,
Matt

Posted on
Wed Jan 30, 2008 11:44 am
bob offline
User avatar
Posts: 500
Joined: Jun 14, 2006

(No subject)

After compiling the Applescript and running it, it sets all the flags to FF but when it goes to set the flags to an X10 address I get an error "Can't get text 1 of "A1". for the line "set houseASCIICode to text 1 of X10address"

bob

Posted on
Wed Jan 30, 2008 11:51 am
bob offline
User avatar
Posts: 500
Joined: Jun 14, 2006

(No subject)

OK I have the first two bits as FF FF and all the rest as 00 but I still get the error in my previous post.

bob

Posted on
Wed Jan 30, 2008 6:45 pm
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

(No subject)

How about this?
George

Code: Select all
--Second crack at a script to set the X10 filter on the EZX10RF module
--by George Musser
--28 Jan 08

--Running the script clears the X10 filter table and then sets the codes listed in the global array.
--It does *not* create new device links or X10-to-Insteon mappings. To do that, I first need to
--figure out how to do link management.

--The routine has some error-checking, but doesn't work well if there's noise on the line.

--To save you grief, I've commented out two lines that actually do the dirty work, so that you
--can test the script for yourself before setting it loose on your EZX10RF.

--EZX10RF memory map and Insteon command set is available at http://www.simplehomenet.com/Downloads/EZX10RF%20Command%20Set.pdf

property addressEZ : "0C.AF.7D" -- Insteon address of EZX10RF module

--Here's the list of X10 address to allow through.

property X10list : {"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "E4"}

main()

on main()
   --comment this back in when you're ready!
   --clearFlags()
   repeat with currentX10address in X10list
      setFlag(currentX10address, true)
   end repeat
end main

on clearFlags()
   tell application "IndigoServer"
      
      --set starting memory address for subsequent commands
      send insteon raw cmd1 40 cmd2 0 to address addressEZ -- high byte
      send insteon raw cmd1 43 cmd2 6 to address addressEZ -- low byte (starting with house code B for now)
      
      --cycle through the 2-byte registers associated with each X10 house code and clear them
      repeat 32 times
         
         --poke in a 0 value, which turns off filtering for all the unit codes         
         set ack to my getAck(41, 0, addressEZ)
         
         --make sure it cleared properly
         if ack is not 0 then
            log "Unable to verify command"
            exit repeat
         end if
         
      end repeat
      
   end tell
end clearFlags


--here's a kludge to get the ACK code after sending raw Insteon commands
--this requires complete quiet on the power line

on getAck(byte1, byte2, addr)
   tell application "IndigoServer"
      
      --the ulterior purpose of this log command is to ensure that a time stamp doesn't contaminate
      --the ACK line
      log "Ready to send raw insteon"
      
      --here we actually send the command
      send insteon raw cmd1 byte1 cmd2 byte2 to address addr
      
      try
         set ackDec to -1
         
         --wait for the ack to come through
         repeat 8 times
            
            --grab the most recent line of the log
            --unfortunately, the date and time sometimes get mixed in
            set latestLogLine to build event log list line count 1
            
            --is it what we're looking for?
            --is there a better way of doing this?
            if second word of latestLogLine is "INSTEON" then
               if fourth word of latestLogLine is "raw" then
                  if my Hex2Dec(text 54 thru 55 of latestLogLine) is byte1 then
                     if my Hex2Dec(text 57 thru 58 of latestLogLine) is byte2 then
                        set ackDec to my Hex2Dec(last word of latestLogLine)
                        exit repeat
                     end if
                  end if
               end if
            end if
            delay 0.25
         end repeat
         
         if ackDec < 0 or ackDec > 255 then
            return -1
         else
            return ackDec
         end if
      on error
         return -1
      end try
   end tell
end getAck


--set a specific X10 flag on or off
--to enable a unit code, poke a 1 bit at the bit corresponding to the unit
--e.g. 4 corresponds to unit code 3

on setFlag(X10address, newFlag)
   tell application "IndigoServer"
      
      --first, check the arguments
      if class of X10address is not string or class of newFlag is not boolean then return -1
      
      --second, parse the X10 address
      set houseASCIICode to text 1 of X10address
      set houseCode to offset of houseASCIICode in "ABCDEFGHIJKLMNOP"
      if length of X10address is 1 then
         return -1
      else if length of X10address is 2 then
         set unitCode to text 2 of X10address as number
      else
         set unitCode to text 2 thru 3 of X10address as number
      end if
      
      --third, do some error-checking
      if houseCode < 1 or houseCode > 16 or unitCode < 1 or unitCode > 16 then return -1
      
      --fourth, convert to an offset within the EZX10RF table
      set memoryIndex to 2 + houseCode * 2
      if unitCode ≤ 8 then
         set unitCode to unitCode - 1
      else
         set memoryIndex to memoryIndex + 1
         set unitCode to unitCode - 9
      end if
      
      --fifth, read the existing byte
      set reflectedAddress to my getAck(40, 0, addressEZ) -- address MSB
      if reflectedAddress is not 0 then return -1
      set currentByte to my getAck(43, memoryIndex, addressEZ) -- address LSB
      if currentByte is -1 then return -1
      
      --sixth, mask in the new flag value
      set mask to (2 ^ unitCode) as integer
      if newFlag then
         set newByte to my BitwiseOr(currentByte, mask)
      else
         set newByte to my BitWiseAnd(currentByte, my BitwiseNot(mask))
      end if
      
      --seventh, write the byte
      --when you're ready, comment this in and the debug line out
      --send insteon raw cmd1 41 cmd2 newByte to address addressEZ
      
      tell application "Script Editor"
         display dialog "address " & memoryIndex & ", old value " & currentByte & ", new value " & newByte
      end tell
   end tell
end setFlag


--can someone tell me why AppleScript doesn't already have the following operators?
on BitwiseOr(i, j)
   return (do shell script "perl -e 'printf(\"%d\"," & i & "|" & j & ")'") as number
end BitwiseOr

on BitWiseAnd(i, j)
   return (do shell script "perl -e 'printf(\"%d\"," & i & "&" & j & ")'") as number
end BitWiseAnd

on BitwiseNot(i)
   return 256 + (do shell script "perl -e 'printf(\"%d\",~" & i & ")'") as number
end BitwiseNot

--AppleScript stupidly doesn't have native functions for handling hexadecimal, but here's an elegant workaround from http://bbs.applescript.net/viewtopic.php?id=19442
on Hex2Dec(s)
   return (do shell script "perl -e 'printf(hex(\"" & s & "\"))'") as number
end Hex2Dec

Posted on
Wed Jan 30, 2008 7:00 pm
bob offline
User avatar
Posts: 500
Joined: Jun 14, 2006

(No subject)

George,

I still the the same error - Can't get text 1 of "A1".

Also in your script it says;

--seventh, write the byte
--when you're ready, comment this in and the debug line out
--send insteon raw cmd1 41 cmd2 newByte to address addressEZ

Do you mean in the second line to "uncomment the third line (send insteon raw........) ?

bob

Posted on
Wed Jan 30, 2008 7:34 pm
gmusser offline
Posts: 265
Joined: Feb 12, 2005
Location: New Jersey

(No subject)

Hi Bob,
What, if anything, appears in the Indigo log?
George

Who is online

Users browsing this forum: No registered users and 0 guests