Author Topic: Ruby code for EZ-Bridge (Insteon) RC1  (Read 11290 times)

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Ruby code for EZ-Bridge (Insteon) RC1
« on: November 25, 2007, 09:18:24 pm »

See END OF THREAD for most current code.


Here is my beta code for EZBridge.  This code works fairly well.  It's a far cry from my previous attempt(Gimme a break, I was learning Ruby at the same time, and still am).

I have implemented a cmdqueue to queue commands so I can receive the responses in a timely manner.

I still have ONE SMALL question, I hope someone here can answer..

I process the Receive command for Child: all Ok.
I want to tell linuxmce the command was successful.

What device do I send the 'Successful' command?  Or, do I have to send an event?!?

Here's a snippet from my DCERouter log showing the two commands:

Received Message from 41 (Windows XP PC/tablet (Horiz) / Office) to 40 (Office Light / Office), type 1 id 184 Command:Set Level, retry none,
parameters: <0x877ccb90>
08   12/04/07 19:08:53.346        Parameter 76(Level): 100 <0x877ccb90>
08   12/04/07 19:08:56.534      Received Message from 40 (Office Light / Office) to 1 (CORE / Office), type 1 id 184 Command:Set Level, retry none,
parameters: <0x82fc3b90>
08   12/04/07 19:08:56.534        Parameter 76(Level): 100 <0x82fc3b90>

I've tried sending the command to:
1 (CORE/Office),
2 (DCERouter), and
41 (Windows XP PC/tablet (Horiz) / Office)

The commands get sent, but status doesn't get updated...

I'm really fighting with this issue because:
when I click <Light ON> from an orbiter, all is well, (from my log:)

05   12/04/07 18:50:41.630      GSDMessageTranslator isCmdImplemented = false <0xb6010b90>
05   12/04/07 18:50:41.631      #### Pre-Process Queue = 1 <0xb6010b90>
05   12/04/07 18:50:41.651      _QueueProc Pre - 184 : 0 <0xb7813b90>
05   12/04/07 18:50:41.651      GSD-Sleep Pre 184 : 0 <0xb7813b90>
05   12/04/07 18:50:41.651      Process Queue = 1 <0xb7813b90>

when, I click <Light OFF> from said orbiter, I get (in my log):

05   12/04/07 18:50:59.099      GSDMessageTranslator isCmdImplemented = false <0xb6010b90>
05   12/04/07 18:50:59.100      #### Pre-Process Queue = 1 <0xb6010b90>
05   12/04/07 18:50:59.154      _QueueProc Pre - 193 : 0 <0xb7813b90>
05   12/04/07 18:50:59.155      GSD-DispatchMessage - ignoring 193 because is useless. <0xb7813b90>
05   12/04/07 18:50:59.155      _QueueProc Post - 193 : 0 <0xb7813b90>

Now, Here's the problem:  I don't want to send an 'ack' until I've verified the command has sent successfully.  This includes 'process incoming data' routines...

Am I going about this in the wrong way??  do I HAVE to return the 'ack' from within the Process Command for Child (or private methods as needed) ?

Anywho, here's the code snippets..
(There is useless code here, that's beta for you!)

Private Method Listing:
Code: [Select]
#### Written by Dan Damron
#### #373 Private Method Listing ####
#
# Commands send back to DCE
# 184 - SetLevel value 0-100 (% on) or +-1 for steps
# 193 - Turn Light OFF
# 192 - Turn Light ON
#
#
#
#
require "rexml/document"
require "rexml/streamlistener"

include REXML


def EZToDCE(param)
#param contains a hash of EZBridge command structure
log('--|---------EZtoDCE')
checkWait(param)
log('-----:)-----EZtoDCE ' + param['Response'] + ' Received.')
case param['Response']
# Standard Commands (responses to command)
when 'GetRevision' # Special Response
log('-----|---------GetRevision:' + param['Parameter1'])

when 'GetLatLong'  # Special Response
log('-----|---------GetLatLong: Lat=' + param['Lat'] + ', Long=' + param['Long'])

when 'SetLatLong'
if param['Parameter1'] = 'True' then
log('-----|---------SetLatLong: Ok')
else
log('-----X---------SetLatLong: FAILED!')
end
when 'SetPasswd'

when 'SetTimeZone'

when 'GetClock' # Special Response

when 'SetClock'

when 'SetNTPServer'

when 'Upgrade'

when 'NetCfg'

when 'Reset'
sleep 0.5
log('----X-------' + param['Parameter1']) # RestartEZBridge

when 'LstTimers'  # Special Response


when 'ClrTimers'

when 'AddTimer'

when 'GetTimer'    # Special Response

when 'SetTimer'

when 'DelTimer'

when 'GetVersion' # Special Response

when 'SndGrp'

when 'SndIns'

when 'SndX10'

when 'StLnk'

when 'CancelLnk'

when 'SetDev'

when 'RstPLM'

when 'GetLnk'

when 'GetNext'

when 'SetCfg'

when 'GetLnkData'

when 'LEDON'

when 'LEDOFF'

when 'MngLnk'

when 'GetCfg' # Special Response

when 'LstMacros' # Special Response

when 'ClrMacros'

when 'AddMacro'

when 'GetMacro' # Special Response

when 'SetMacro'

when 'DelMacro'

when 'LstDevices' # Special Response

when 'ClrDevices'

when 'AddDevice'

when 'GetDevice' # Special Response

when 'SetDevice'

when 'DelDevice'

when 'LstZones'

when 'ClrZones'

when 'AddZone'

when 'GetZone'

when 'SetZone'

when 'DelZone'

when 'AddDevZone'

when 'DelDevZone'

# Response Messages
when 'InsStdMsg'

when 'InsExtMsg'

when 'X10Msg'

when 'InsLnkSts'

when 'BtnRpt'

when 'UsrRst'

when 'GrpEvntRpt'

when 'LnkData'

# Other messages
when 'PLMEchoError' # I know theres a PLM comm error...
# error sending command to PLM, reset command and try again
log('-----X------' + param['Response'])
resetcmd = {'Command' => 'Reset'}
$cmdqueue.insert(0, resetcmd)
sleep 0.1
$wAIT = false
SndIns()
when 'LongAck'
log('-----X------' + param['Response'])
# Error - seems to show up after PLMEchoError
resetcmd = {'Command' => 'Reset'}
$cmdqueue.insert(0, resetcmd)
sleep 0.1
$wAIT = false
SndIns()
else
log('-----XXXXXXX UNKNOWN Response Received:' + param['Response'])
end

end
def checkWait(param)
#Checks for response from current command.
if $cmdqueue[0] != nil
log('---|--------CheckWait:')
log('---|--------Current Command:' + $cmdqueue[0]['Command'])
log('---|--------param:' + param['Response'])
log('---|--------Flag:'+ $wAIT.to_s)
if $cmdqueue[0]['Command'] == param['Response']
$wAIT = false
log('---|--------Current Command Queue Length Before Delete:' + $cmdqueue.nitems.to_s)
$cmdqueue.delete_at(0)
log('---|--------Flag & currentCmd cleared')
log('---|--------Current Command Queue Length:' + $cmdqueue.nitems.to_s)
if $cmdqueue.nitems > 0 then
SndIns()
end
end
else
log('------:)----checkWait: command queue is emtpy')
if $wAIT == true
log('------:(----CheckWait: TRUE')
else
log('------:)----CheckWait: TRUE')
end
end
end

def parseMessage(param)
param.keys.each{|p| log("PM Param:" + p.to_s + "=" + param[p].to_s)}
case param['Response']
when 'SndIns' # response message
$wAIT = false
insHb = param['Parameter3'] # From
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = 2 #DCE Router
myPriority = 1
myType = 1 # Command

#####log('Parent:' + parent_) -- this crashes the code

case param['Parameter7']
when '11' # dim/Brighten
myID = 184
log('From:' + myDevFrom.to_s)
log('To:' + myDevTo.to_s)
log('Pri:' + myPriority.to_s)
log('Type:' + myType.to_s)
log('ID:' + myID.to_s)
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 184)
cmd.params_[184] = hextopercent(param['Parameter8']).to_s
SendCommand(cmd)
log('SENT!!!..............')
when '13' # off
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 193)
SendCommand(cmd)
when '12' # on
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 192)
SendCommand(cmd)
end
when 'InsStdMsg'
insHb = param['Parameter3']
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = 2 #DCE Router
myPriority = 1
myType = 1 # Command
myID = InsCmdtoID(param['Parameter10'])


$wAIT = false
when 'InsExtMsg'
$wAIT = false
when 'X10Msg'
$wAIT = false

when 'InsLnkSts'
$wAIT = false
when 'BtnRpt'
$wAIT = false
when 'UsrRst'
$wAIT = false
when 'GrpEvntRpt'
$wAIT = false
when 'LnkData'
$wAIT = false
when 'GetVersion'
$wAIT = false
when 'GetCfg'
$wAIT = false
when 'LstTimers'
$wAIT = false
when 'GetTimer'
$wAIT = false
when 'GetRevision'
$wAIT = false
when 'GetLatLong'
$wAIT = false
when 'GetClock'
$wAIT = false
when 'LstMacros'
$wAIT = false
when 'GetMacro'
$wAIT = false
when 'LstDevices'
$wAIT = false
when 'GetDevice'
$wAIT = false
else
log('*#*#*#*#*#*#*#UNKNOWN COMMAND*#*#*#*#*#*#')
log(param['Response'])
$wAIT = false
end
end



def InsCmdtoID(value)
case value
when '01' # Assign to (Insteon) Group
return 0
when '02' # Delete from (Insteon) Group
return 0
when '10' # Ping
return 0
when '11' # ON
return 192
when '13' # OFF
return 193
when '15' # Brighten 1 step
return 0
when '16' # Dim 1 step
return 0
when '17' # Start Manual Change
return 0
when '18' # Stop Manual Change
return 0
when '19' # Status Request
return 0
when '24' # Do EE READ
return 0
when '28' # Set Address MSB
return 0
when '29' # POKE
return 0
when '2A' # POKE Extended
return 0
when '2B' # PEEK
return 0
when '2C' # PEEK Internal
return 0
when '2D' # POKE internal
return 0
else
return 0
end

end

def rawX10(value)

x10MSN = $X10HouseCodes.index[value[0..0]]
x10LSN = $X10UnitCodes.index[value[1..1]]
return x10MSN + x10LSN
end
def X10Flag(value)
  return + $X10CommandCodes.index[Value] + '0'
end

def SndIns
# create a new XML command for SndIns
log('|-----------SndIns:WAIT FLAG = ' + $wAIT.to_s)
if $wAIT == false
param = $cmdqueue[0]
log('|-----------SndIns: Items in queue:' + $cmdqueue.nitems.to_s)
doc = Document.new
doc << XMLDecl.new
el = doc.add_element 'command'
el.text = param['Command']
param.keys.each {|k|
#log('|-----------SndIns:param[' + k.to_s + ']=' + param[k].to_s)
if k != 'Command' then
el1 = el.add_element k
el1.text = param[k]
end
}
conn_.Reconnect()
conn_.Send(doc.to_s)
log('Out---------SndIns:CmdSent:' + doc.to_s)

$wAIT = TRUE
else
log('X-----------SndIns: Waiting for response to:' +  $cmdqueue[0]['Command'].to_s)
log('X-----------SndIns: Current Queue Length:' + $cmdqueue.nitems.to_s)
end
end

def padhex(hex)
if hex.length==1
hex = "0" + hex
end
return hex
end

def percenttohex(level)
# convert from percent to byte
return "%X" %((level.to_i * 2.56) -1).to_i
end

def hextopercent(level)
return (level.hex.to_i / 2.55).to_i
end

def log(line)
$log = File.open("/var/log/pluto/39_Generic_Serial_Device.log", "a")
$log.puts "(***):" + line.to_s
$log.close
end

Process Incoming Data:
Code: [Select]
#### Written by Dan Damron
#### #350 Process Incoming Data ####


#$recvBuff = ''
#while (true)
# buff = conn_.RecvDelimited($responseString, 100)
# if (buff.length() == 0)
# break
# end
# $recvbuff = $recvbuff + buff
#end

log('In----------Processing Incoming Data')
while(true)
    buff=conn_.Recv(128,100)
    if(buff.length() == 0)
        break
    end
    $recvbuff = $recvbuff + buff
end

$recvbuff = parsestring($recvbuff)

Process Initialize:

Code: [Select]
#### Written by Dan Damron
#### #355 Process Initialize ####
$log = ''
$cmdTo = ''
$cmdFrom = ''
$cmdPriority = ''
$cmdType = ''
$cmdID = ''
$cmdParams = {}
$children = {}
$recvbuff = ''
$wAIT = false
$currentCmd = {}
$flagsBroadcastMessage = 128
$flagsDirectMessage = 0
$flagsAckDirectMessage = 32
$flagsNackDirectMessage = 160
$flagsGroupBroadcaseMessage = 192
$flagsGroupCleanupDirectMessage = 64
$flagsGroupAckDirectMessage =96
$flagsGroupNackDirectMessage = 224
$cmdqueue = []
$dcequeue = []
$X10HouseCodes = {
'6', 'A',
'E', 'B',
'2', 'C',
'A', 'D',
'1', 'E',
'9', 'F',
'5', 'G',
'D', 'H',
'7', 'I',
'F', 'J',
'3', 'K',
'B', 'L',
'0', 'M',
'8', 'N',
'4', 'O',
'C', 'P'}
$X10UnitCodes = {'6', '1', 'E', '2', '2', '3', 'A', '4',
'1', '5', '9', '6', '5', '7', 'D', '8',
'7', '9', 'F', '10', '3', '11', 'B', '12',
'0', '13', '8', '14', '4', '15', 'C', '16'}
$X10CommandCodes = {'6', 'All Lights Off', 'E', 'Status = off',
'2', 'On', 'A', 'Pre-Set Dim',
'1', 'All Lights On', '9', 'Hail Ack',
'5', 'Bright', 'D', 'Status=on',
'7', 'Extended Code','F', 'Status Request',
'3', 'Off', 'B', 'Pre-set Dim',
'0', 'All Units Off', '8', 'Hail Request',
'4', 'Dim', 'C', 'Extended Data(analog)'}
$responseString = '<' + '/' + 'Response>'
log('Finding Children..')
device_.childdevices_.each{|c|
log(c.to_s.to_i)
log(device_.childdevices_[c.to_s.to_i].devdata_[12])
$children[device_.childdevices_[c.to_s.to_i].devdata_[12].chomp.lstrip.rstrip] = c.to_s.to_i
}
$children.keys.each{|c| log(c + ' = ' + $children[c].to_s)}


Process Command for Child:
Code: [Select]
#### Written by Dan Damron
#### #384 Process Receive Command for Child ####


log('------dce--- PRCFC:$wAIT=' + $wAIT.to_s)
#add DCE command to DCE queue




insteonID = device_.childdevices_[cmd.devidto_].devdata_[12].chomp.split('.')
$cmdID = cmd.id_
$cmdTo = cmd.devidto_
childType = device_.childdevices_[cmd.devidto_].devtemplid_
$cmdFrom = cmd.devidfrom_
$cmdPriority = cmd.priority_
$cmdType = cmd.type_
$cmdParams = cmd.params_
log('------dce--- cmdID:' + $cmdID.to_s + ', cmdFrom:' + $cmdFrom.to_s + ', cmdTo:' + $cmdTo.to_s + ', cmdType:' + $cmdType.to_s + ', Priority:' + $cmdPriority.to_s)
$cmdParams.keys.each {|p| log('------dce--- Param_[' + p.to_s + ']=' + $cmdParams[p])}
case cmd.id_
when 192 # ON
if insteonID.length > 2 then

param = {'Command' => 'SndIns',
'Parameter1' => insteonID[0],
'Parameter2' => insteonID[1],
'Parameter3' => insteonID[2],
'Parameter4' => '0F',
'Parameter5' => '11',
'Parameter6' => 'FF'}
$cmdqueue << param
SndIns()
else
log "------dce--- X10 DEVICE!!!"


param = {'Command' => 'SndX10',
'Parameter1' => rawX10(device_.childdevices_[cmd.devidto_].devdata_[12]),
'Parameter2' => X10Flag('On')}
$cmdqueue << param
SndIns()
end
resp = Command.new($cmdTo, 1, $cmdPriority, $cmdType, $cmdID)
resp.params_ = $cmdParams
SendCommand(resp)
when 193 #OFF
if insteonID.length > 2 then

param = {'Command' => 'SndIns',
'Parameter1' => insteonID[0],
'Parameter2' => insteonID[1],
'Parameter3' => insteonID[2],
'Parameter4' => '0F',
'Parameter5' => '13',
'Parameter6' => '00'}
$cmdqueue << param
SndIns()
else
log "------dce--- X10 DEVICE!!!"
param = {'Command' => 'SndX10',
'Parameter1' => rawX10(device_.childdevices_[cmd.devidto_].devdata_[12]),
'Parameter2' => X10Flag('Off')}
$cmdqueue << param
SndIns()

end
resp = Command.new($cmdTo, 1, $cmdPriority, $cmdType, $cmdID)
resp.params_ = $cmdParams
SendCommand(resp)

when 184 #SetLevel
# convert from percent to hex
dim_level = percenttohex(cmd.params_[76])
log("------dce--- Dim Level:" + dim_level.to_s)
if insteonID.length > 2 then

param = {'Command' => 'SndIns',
'Parameter1' => insteonID[0],
'Parameter2' => insteonID[1],
'Parameter3' => insteonID[2],
'Parameter4' => '0F',
'Parameter5' => '11',
'Parameter6' => dim_level}
$cmdqueue << param
SndIns()
else
log "X10 DEVICE!!! relative Dimming command"
# have to send 2 commands
#param = {'Command' => 'SndX10',
#'Parameter1' => rawX10(device_.childdevices_[cmd.devidto_].devdata_[12]),
#'Parameter2' => $X10CommandCodes.index['Bright'] + $X10UnitCodes.index[dim_level]
#$cmdqueue << param
#param = {'Command' => 'SndX10',
#dim_level = ((cmd.params_[76] * 16 + 1)/100).to_i.to_s
#'Parameter1' => rawX10(device_.Childdevices_[cmd.devidto_].devdata_[12]),
#'Parameter2' => $X10CommandCodes.index['Dim'] + $X10UnitCodes.index[dim_level]}

SndIns()

end
resp = Command.new($cmdTo, 1, $cmdPriority, $cmdType, $cmdID)
resp.params_ = $cmdParams
SendCommand(resp)
end
« Last Edit: December 12, 2007, 11:29:46 pm by ddamron »
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #1 on: December 05, 2007, 04:25:52 am »
Bump (modified original message)
Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

tschak909

  • LinuxMCE God
  • ****
  • Posts: 5495
  • DOES work for LinuxMCE.
    • View Profile
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #2 on: December 05, 2007, 02:03:12 pm »
dude, that's awesome.. i don't have any insteon devices yet, or i'd be trying it right now!

-Thom

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #3 on: December 05, 2007, 04:59:27 pm »
Thanks Thom!

Still waiting to see if anyone knows the answer to my question...

I'm starting work on the PLM (serial) now.

with the code I've already done, it should go pretty quick.. a few days..
will post it too!
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

bulek

  • Administrator
  • wants to work for LinuxMCE
  • *****
  • Posts: 884
  • Living with LMCE
    • View Profile
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #4 on: December 05, 2007, 11:14:42 pm »
Hi,

I've done similar code in Perl for my home automation system from Cybrotech. And basically events do change state of device.

For instance :
- you send on command to light and then return event with light being on and then state will change - although currently majority of home automation systems aren't two way, so light switch at the moment is designed to make transition by itself - but if you send event also it will change it's state accordingly.

For sensors like temperature, brightness, thermostat setpoint you just send proper events about their current state ("temperature changed" for instance)...

See this :
http://wiki.linuxmce.org/index.php/Sensors
http://wiki.linuxmce.org/index.php/MessageSend
http://wiki.linuxmce.org/index.php/DCE_from_commandline

and make few tests with sending events/commands - you easily see what works and what doesn't...

HTH,

regards,

Bulek.
Thanks in advance,

regards,

Bulek.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #5 on: December 06, 2007, 03:07:56 am »
Bulek,

THANK YOU!

I could not find that info anywhere... now I just need to track down which events to fire for each command...

and who do I send the event to?  DCERouter I'm guessing...

Can I send 2 seperate events.. 1 for 'Command Sent Successfully' and the other for 'Command Executed Successfully'?  I just noticed the links you said to see.. I'll investigate those now...

again,

THANK YOU!

Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #6 on: December 06, 2007, 04:11:57 am »
Ok, I think I understand the Events... sort of...
I now know to fire the event to device ID -1000 (hardcoded to DCERouter)

I understand how to fire an event.
looking at the zwave device template, I found the device on/off event.
I understand (if I'm not mistaken) I have to create a new event:
1.  'Report Light On-Level' (#75)
with parameters:
2.  'value' # 30
with text description of 'value of On-Level percent 0 to 100%'

Now, do I create that event in :
A:  the actual child device (light switch, dimmable),
B:  the EZBridge device (GSD)
C:  or both?

Once the event is created, what must I do to allow DCERouter to respond to (a new event)?

Thanks so much for your help in pointing me in the right direction...

Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #7 on: December 06, 2007, 08:28:23 pm »
Trial and error provided me with:

1.  The event must be fired from the CHILD DEVICE, not the parent.
2.  Sending the event to -1000 reports (in the log) as UNKNOWN, but dcerouter seems to get it (I can change light status ON/OFF)
3.  My newly created event fires correctly, however I don't understand how to tell dcerouter:

 "When you hear THIS event, Set the senders INTERNAL Light Level value to this events parameter value!'

ie:  device:40 (Office Light) when Event:75 (Report Light On-Level) fires from  with parameter:30 (value)s value set to 50

07   12/06/07 11:57:16.958      Event #75 has no handlers <0x6699bb90>
07   12/06/07 11:57:16.958      Received Message from 40 (Office Light / Office) to -1000 (unknown / ), type 2 id 75 Event:Report Light On-Level, retry none, parameters: <0x6699bb90>
07   12/06/07 11:57:16.958        Parameter 30(Value): 50 <0x6699bb90>

Thanks ahead of time! 
BTW, PLM integration is well on it's way...
I've learned more ruby, and code is again (!) much much more object oriented.
I've created self validating command objects to handle all the PLM communication, and all the fields IN those command objects are also self-validating... with all kinds of methods to insert and extract data.

I've currently created class files for:
InsteonID
InsteonFlags
InsteonCmdByte
InsteonExtendedData
X10Translations
InsStdCmd (Insteon Standard Command)

etc.etc.etc..





The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

bulek

  • Administrator
  • wants to work for LinuxMCE
  • *****
  • Posts: 884
  • Living with LMCE
    • View Profile
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #8 on: December 06, 2007, 11:18:23 pm »
Hi,

usually DCERouter only reroutes events to coresponding plugins to act upon (I guess lighting plugin should be addressed in this case, but also it should understand it )...

I'm not sure, but it seems like event #75 ix not yet supported (or better said - it's not routed further to some plugin that would understand it...). And if it were, current state for lights is not shown on Orbiter anyway - so other changes in code are also needed... Maybe for now you can try to put current level into device state directly, not via plugin...

Currently support for events is quite limited and one can get a lot of frustrations when trying to add support for something new (it's almost a year since I began my efforts in adding "brightness changed" event, but it's still not supported properly - I must say that any new event has to be added to main database and code base so one can implement support for it - so things are sometimes slower from our expectations)...

Anyway, to speed up such thing, I've written several feature requests and forum threads and did a lot of discussion sessions with Pluto guys, but things are going slowly- although we came to somekind of agreement that this problem need to be addressed as soon as possible, cause only few devices are currently properly shown on Floorplan and can be controlled from there... My proposition is described here :
http://mantis.linuxmce.org/view.php?id=3456

Please put as much info as possible about your work - it will be tremendously useful for other potential contributors...

HTH,

regards,

Bulek.
Thanks in advance,

regards,

Bulek.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #9 on: December 07, 2007, 02:41:25 am »
Thanks Bulek, Great reply..

Digging around I found the event system..under Advanced/Configuration/Events...

Yes, Event # 75 is new - I created it and added it to my device template #38 Light Switch (dimmable), which, SHOULD filter down to all my lighting devices...

looking closer, I see that the piece of data I want to change is the STATE (string)...

I've coded almost 1200 lines of NEW code for Insteon PLM interface.. and still not done...line #1131 is where my class objects STOP (so far)

I've got about 8 more objects to create <Phew> before I can start testing to make sure the 'glue' is right from object to object.

I'll keep digging around the advanced event system to see if I can find a command to change a devices state..

Thanks again for all your help...

really apreciate the input.

Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #10 on: December 07, 2007, 03:02:02 am »
Bulek,

There's got to be a way to do it... Orbiters do it..
I can see the state of the light in the Devices/Lights/advanced.. under Device Info.. at the bottom... state (mine currently says ON/50)

The orbiters DO use this if you use a fiire chief remote, and momentarily press VOL&LIGHT and wave up/down..
you can see the state change on the left side of the screen..

There's got to be something I'm (we're) missing.. lemme find out exactly what an orbiter does when you change the 'state'

unless it's a one-way value... hmmm.. that could be it.. but should I not be able to fire a command based on an event?

Yes, I can do that, I saw it in the advanced events.. but the trick here is.. can I fire a command based on an event's parameters.... hmmm....

Brainstorming here.... anyone else have any suggestions??

BTW, I think I figured out how to add an event handler for a custom event, so that part shouldn't be too hard...

HTH,
Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #11 on: December 07, 2007, 05:49:11 am »
K, I'm tired, just another 200 lines of code to total 1400.
Started testing the 'glue', all seems ok so far.. only tested 5 command objects.

For those of you who are following this...  here's my code so far...
WTF!@! Grrr....

The code is too big to fit in the message :(
anyone know how I can do this??  I get an error message saying that the message max is 20000 bytes..

Ahh well, I'll just attach it then... hehe

I'll be awake for about another hour... if you get a chance to reply, please do!  I LOVE to hear comments / suggestions...

TTYL

Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

bulek

  • Administrator
  • wants to work for LinuxMCE
  • *****
  • Posts: 884
  • Living with LMCE
    • View Profile
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #12 on: December 07, 2007, 09:13:40 am »
Hi,

I'm not sure if any changes will appear in 710, but we agreed with developers, that maybe Climate and Lighting plugin will go in direction described in mantis feature request - so they will draw device's state on Floorplan whatever it is... we will see what happens...

Till then you can change device state directly in sql database with sql statement...


...

There's got to be something I'm (we're) missing.. lemme find out exactly what an orbiter does when you change the 'state'

unless it's a one-way value... hmmm.. that could be it.. but should I not be able to fire a command based on an event?

Yes, I can do that, I saw it in the advanced events.. but the trick here is.. can I fire a command based on an event's parameters.... hmmm....

Brainstorming here.... anyone else have any suggestions??

BTW, I think I figured out how to add an event handler for a custom event, so that part shouldn't be too hard...

HTH,
Dan

Not sure why do you need that (I guess you want to add event handler over web-admin? ). Otherwise you can send any command you want from your gsd device, but that's probably not what you're looking for....

Hmm, I still need to take Ruby lessons to be able to do something usefull with GSD...

Regards,

Bulek.
Thanks in advance,

regards,

Bulek.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
Re: Beta Ruby code for EZ-Bridge (Insteon)
« Reply #13 on: December 07, 2007, 06:15:42 pm »
Bulek,

Thanks again for all your info..  and Yes, I agree about the Lighting and Climate plugins.  I will make my views known in mantis, but I want to finish this code first.

I think I have the rest of it down... we'll see once I start implementing this code..

Dan
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.

ddamron

  • Alumni
  • wants to work for LinuxMCE
  • *
  • Posts: 962
    • View Profile
    • My LinuxMCE User Page
RC1 Ruby code for EZ-Bridge (Insteon)
« Reply #14 on: December 12, 2007, 11:26:50 pm »
here they are...

Code: [Select]
#### Written by Dan Damron
#### #373 Private Method Listing ####
#
# Commands send back to DCE
# 184 - SetLevel value 0-100 (% on) or +-1 for steps
# 193 - Turn Light OFF
# 192 - Turn Light ON
#
#
#
#
require "rexml/document"
require "rexml/streamlistener"

include REXML


def EZToDCE(param)
#param contains a hash of EZBridge command structure
log('--|---------EZtoDCE')
log('Queue:' + $cmdqueue[0].inspect)
log('Param:' + param.inspect)
checkWait(param)
case param['Response']
# Standard Commands (responses to command)
when 'GetRevision' # Special Response
log('-----|---------GetRevision:' + param['Parameter1'])

when 'GetLatLong'  # Special Response
log('-----|---------GetLatLong: Lat=' + param['Lat'] + ', Long=' + param['Long'])

when 'SetLatLong'
if param['Parameter1'] = 'True' then
log('-----|---------SetLatLong: Ok')
else
log('-----X---------SetLatLong: FAILED!')
end
when 'SetPasswd'

when 'SetTimeZone'

when 'GetClock' # Special Response

when 'SetClock'

when 'SetNTPServer'

when 'Upgrade'

when 'NetCfg'

when 'Reset'
#Reset Response
cmdComplete
when 'LstTimers'  # Special Response


when 'ClrTimers'

when 'AddTimer'

when 'GetTimer'    # Special Response

when 'SetTimer'

when 'DelTimer'

when 'GetVersion' # Special Response

when 'SndGrp'

when 'SndIns' # response from SndIns
#First, check the response to make sure the command made it ok.
if param['Parameter9'].to_i == 6 #Ack received
case param['Parameter7'].hex #Received an ack to THIS command
when '1'.hex #Assign to Group
when '2'.hex #Delete from Group
when '10'.hex # PING
when '11'.hex #ON
$currentcmd = 11
$cmdqueue[0]['Command'] = 'InsStdMsg'
when '13'.hex #OFF
$currentcmd = 13
$cmdqueue[0]['Command'] = 'InsStdMsg'
when '15'.hex #Bright
$currentcmd = 15
$cmdqueue[0]['Command'] = 'InsStdMsg'
when '16'.hex #DIM
$currentcmd = 16
$cmdqueue[0]['Command'] = 'InsStdMsg'
when '17'.hex #Start Manual Change
when '18'.hex #Stop Manual Change
when '19'.hex #Status Request
# Status Request Acked - get ready for InsStdMsg
$currentcmd = 19
# change cmd to reflect InsStdMsg
$cmdqueue[0]['Command'] = 'InsStdMsg'
when '24'.hex
log('Caught ACK for Insteon DO EE READ')
when '28'.hex
log('Caught ACK for Insteon SET ADDRESS MSB')
when '29'.hex
log('Caught ACK for Insteon POKE')
when '2A'.hex
log('Caught ACK for Insteon POKE EXTENDED')
when '2B'.hex
log('Caught ACK for Insteon PEEK')
when '2C'.hex
log('Caught ACK for Insteon PEEK INTERNAL')
when '2D'.hex
log('Caught ACK for Insteon POKE INTERNAL')
else
log('Unknown Insteon Cmd1')
end

else # NACK received - command failed.
end

when 'SndX10'

when 'StLnk'

when 'CancelLnk'

when 'SetDev'

when 'RstPLM'

when 'GetLnk'

when 'GetNext'

when 'SetCfg' # response from Setcfg command
if param['Parameter4'].to_i == 6 #ack
log('SetCfg Completed')
cmdComplete
else
log('SetCfg NACKED')
end
when 'GetLnkData'

when 'LEDON'

when 'LEDOFF'

when 'MngLnk'

when 'GetCfg' # Special Response

when 'LstMacros' # Special Response

when 'ClrMacros'

when 'AddMacro'

when 'GetMacro' # Special Response

when 'SetMacro'

when 'DelMacro'

when 'LstDevices' # Special Response

when 'ClrDevices'

when 'AddDevice'

when 'GetDevice' # Special Response

when 'SetDevice'

when 'DelDevice'

when 'LstZones'

when 'ClrZones'

when 'AddZone'

when 'GetZone'

when 'SetZone'

when 'DelZone'

when 'AddDevZone'

when 'DelDevZone'

# Response Messages
when 'InsExtMsg'

when 'InsStdMsg'
case $currentcmd # if this msg is part of a response, the Insteon Cmd1 will be saved here.
when 0
#there is no current command
# THIS IS COMING FROM AN OUTSIDE SOURCE
#EG: Manually turning Light Switch On/Off
# process this command.
# Note, this is a standard message
# there is no ack here.  Simply Send EVENTS back to DCE
# and Complete the command.
case param['Parameter10'].hex #this is the command
when '1'.hex #Assign to Group
log('Caught EXTERNAL Assign to Group')
when '2'.hex #Delete from Group
log('Caught EXTERNAL Delete from Group')
when '10'.hex # PING
log('Caught EXTERNAL Insteon PING result')
when '11'.hex #ON
log('Caught EXTERNAL Insteon ON command result')
#on level is in cmd2
insHb = param['Parameter3'] # From
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = -1000 #DCE Router
myPriority = 1
myType = 2 #Event
#Send an EVENT
#Event #48, pipe 10, value 1=on, 2=off
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 48) #Event
cmd.params_[10] = '1' # EVENT ON
SendCommand(cmd)
$currentcmd = 0
cmdComplete
log('EVENT SENT!!!.48:[10]=1')


when '13'.hex #OFF
log('Caught EXTERNAL Insteon OFF result')
#on level is in cmd2
insHb = param['Parameter3'] # From
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = -1000 #DCE Router
myPriority = 1
myType = 2 #Event
#Send an EVENT
#Event #48, pipe 10, value 1=on, 2=off
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 48) #Event
cmd.params_[10] = '0' # EVENT OFF
SendCommand(cmd)
$currentcmd = 0
cmdComplete
log('EVENT SENT!!!.48:[10]=0')


when '15'.hex #Bright
log('Caught EXTERNAL Insteon Brighten Result')
when '16'.hex #DIM
log('Caught EXTERNAL Insteon DIM Result')
when '24'.hex
log('Caught EXTERNAL Insteon DO EE READ')
when '28'.hex
log('Caught EXTERNAL Insteon SET ADDRESS MSB')
when '29'.hex
log('Caught EXTERNAL Insteon POKE')
when '2A'.hex
log('Caught EXTERNAL Insteon POKE EXTENDED')
when '2B'.hex
log('Caught EXTERNAL Insteon PEEK')
when '2C'.hex
log('Caught EXTERNAL Insteon PEEK INTERNAL')
when '2D'.hex
log('Caught EXTERNAL Insteon POKE INTERNAL')
else
log('Unknown EXTERNAL Insteon Command.')
end
when 1 #Assign to Group
when 2 #Delete from Group
when 11 # ON
log('Caught Insteon ON from EXTERNAL source')
insHb = param['Parameter3'] # From
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = -1000 #DCE Router
myPriority = 1
myType = 2 #Event
#Send an EVENT
#Event #48, pipe 10, value 1=on, 2=off
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 48) #Event
cmd.params_[10] = '1' # EVENT ON
SendCommand(cmd)
$currentcmd = 0
cmdComplete
log('EVENT SENT!!!.48:[10]=1')
when 13 # OFF
insHb = param['Parameter3'] # From
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = -1000 #DCE Router
myPriority = 1
myType = 2 #Event
#Send an EVENT
#Event #48, pipe 10, value 1=on, 2=off
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 48) #Event
cmd.params_[10] = '0' # EVENT OFF
SendCommand(cmd)
$currentcmd = 0
cmdComplete
log('EVENT SENT!!!.48:[10]=0')
when 19 # Status Report
insHb = param['Parameter3'] # From
insMb = param['Parameter4']
insLb = param['Parameter5']
insID = insHb + "." + insMb + "." + insLb
myDevFrom = $children[insID]
myDevTo = -1000 #DCE Router
myPriority = 1
myType = 2 #Event
#Send an EVENT
#Event #48, pipe 10, value 1=on, 2=off
cmd = Command.new(myDevFrom, myDevTo, myPriority, myType, 48) #Event
#cant send dim value, only on or off
#cmd.params_[184] = hextopercent(param['Parameter8']).to_s
if param['Parameter11'].hex.to_i == 0 #if off
cmd.params_[10] = '0' # Send Event OFF
else
cmd.params_[10] = '1' # otherwise, send EVENT ON
end
log('Parameter11 = ' + param['Parameter11'].to_s)
log('Params_[10] = ' + cmd.params_[10].to_s)
SendCommand(cmd)
log('EVENT SENT!!!..............')
# now to clear the currentcmd and remove command from the queue
$currentcmd = 0
cmdComplete
else
end

when 'X10Msg'
log('X10 Message Received')

when 'InsLnkSts'

when 'BtnRpt'

when 'UsrRst'

when 'GrpEvntRpt'
log('Group Event Report Received')

when 'LnkData'
#Caught a LnkData Response
log('LnkData Message Received')

# Other messages
when 'PLMTimeout'
log('PLM Timeout detected.. resetting EZBridge')
resetcmd = {'Command' => 'Reset'}
$cmdqueue.insert(0, resetcmd)
sleep 15
$wAIT = false
SndIns()
when 'PLMEchoError' # Have not seen this since a1.23
# error sending command to PLM, reset command and try again
log('-----XXXXXXX' + param['Response'])
resetcmd = {'Command' => 'Reset'}
$cmdqueue.insert(0, resetcmd)
sleep 15
$wAIT = false
SndIns()
when 'LongAck'
log('-----XXXXXXX' + param['Response'])
# Error - seems to show up after PLMEchoError
resetcmd = {'Command' => 'Reset'}
$cmdqueue.insert(0, resetcmd)
sleep 15
$wAIT = false
SndIns()
else
log('-----XXXXXXX UNKNOWN Response Received:' + param['Response'])
end

end
def cmdComplete
# Clears the wait flag, and removes the command from the queue.
$wAIT = false
$cmdqueue.delete_at(0)
# now that THAT command is completed, check to see if there is
# another command ready to transmit.
log ("Command Completed.  Checking queue")
if $cmdqueue.nitems > 0 then
log("Queue:" + $cmdqueue.nitems.to_s + " : executing next command")
SndIns()
else
log ('Queue Empty.')
end
end
def checkWait(param)
#Checks for response from current command.
if $cmdqueue[0] != nil
else
log('------:)----checkWait: command queue is emtpy')
if $wAIT == true #this should never happen
log('------:(XXX-CheckWait: TRUE')
else
log('------:)----CheckWait: FALSE')
end
end
end
def parsestring(value)
## This routine simply extracts complete XML messages
### Could not use RecvDelimited in PID as duplicate messages came through

  param = {}
 ar = value.split($responseString, -1)

  if ar.nitems < 2 then
      value = ar[0]
  else
      value = ar.delete_at(ar.nitems - 1)
      ar.each{|p| p = p + $responseString
      doc = Document.new p
      command = doc.root.get_text.value.to_s
      param['Response'] = command.chomp.lstrip.rstrip

      if doc.root.has_elements? then
#has elements
el = doc.root.elements[1]
while el != nil
          elname = el.name.to_s
          eltext = padhex("%X" %doc.root.elements[elname].text.to_s.hex)
          param[elname] = eltext
          el = doc.root.elements[elname].next_element
end
      end
#parseMessage(param)
EZToDCE(param)
}
    end
return value
end




def InsCmdtoID(value)
case value
when '01' # Assign to (Insteon) Group
return 0
when '02' # Delete from (Insteon) Group
return 0
when '10' # Ping
return 0
when '11' # ON
return 192
when '13' # OFF
return 193
when '15' # Brighten 1 step
return 0
when '16' # Dim 1 step
return 0
when '17' # Start Manual Change
return 0
when '18' # Stop Manual Change
return 0
when '19' # Status Request
return 0
when '24' # Do EE READ
return 0
when '28' # Set Address MSB
return 0
when '29' # POKE
return 0
when '2A' # POKE Extended
return 0
when '2B' # PEEK
return 0
when '2C' # PEEK Internal
return 0
when '2D' # POKE internal
return 0
else
return 0
end

end

def rawX10(value)

x10MSN = $X10HouseCodes.index[value[0..0]]
x10LSN = $X10UnitCodes.index[value[1..1]]
return x10MSN + x10LSN
end
def X10Flag(value)
  return + $X10CommandCodes.index[Value] + '0'
end

def SndIns
# create a new XML command for SndIns
if $wAIT == false
param = $cmdqueue[0]
doc = Document.new
doc << XMLDecl.new
el = doc.add_element 'command'
el.text = param['Command']
param.keys.each {|k|
if k != 'Command' then
el1 = el.add_element k
el1.text = param[k]
end
}
conn_.Reconnect()
conn_.Send(doc.to_s)
log('Out---------SndIns:CmdSent:' + doc.to_s)
sleep 1
$wAIT = TRUE
else
log('X-----------SndIns: Waiting for response to:' +  $cmdqueue[0]['Command'].to_s)
log('X-----------SndIns: Current Queue Length:' + $cmdqueue.nitems.to_s)
end
end

def padhex(hex)
if hex.length==1
hex = "0" + hex
end
return hex
end

def percenttohex(level)
# convert from percent to byte
return "%X" %((level.to_i * 2.56) -1).to_i
end

def hextopercent(level)
return (level.hex.to_i / 2.55).to_i
end

def log(line)
$log = File.open("/var/log/pluto/39_Generic_Serial_Device.log", "a")
$log.puts "(***):" + line.to_s
$log.close
end

Code: [Select]
#### Written by Dan Damron
#### #351 Process IDLE ####
############################ RECEIVE Error Trap ###########################
if  $cmdqueue.length != 0
if $cmdqueue == $savedstate
if $resetNext == 5
#Command has stalled. Reset wait flag and resend command.
log('Command Stalled!  resetting and retrying')
if $cmdqueue[0]['Command'] == 'InsStdMsg'
$cmdqueue[0]['Command'] = 'SndIns'
end
$wAIT = false
$resetNext = 0
SndIns()
else
$resetNext +=1
end
else
$resetNext = 0
$savedstate = $cmdqueue
end
end
###########################################################################
Continued in next message
The only intuitive interface is the nipple.  After that it's all learned.
My other computer is your windows box.
I'm out of my mind.  Back in 5 minutes.
Q:  What's Red and smells like blue paint?

A:  Red Paint.