Difference between revisions of "Insteon PLM Ruby Code 373"
From LinuxMCE
(Added category: GSD) |
|||
(9 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
− | <pre> | + | {{Versioninfo}} |
− | #### Written by Dan Damron | + | [[category: Insteon]] |
+ | [[Category: GSD]] | ||
+ | <pre>#### Written by Dan Damron | ||
#### #373 Private Method Listing #### | #### #373 Private Method Listing #### | ||
def mainStart() ## This is called FIRST, reruns cannot call this. | def mainStart() ## This is called FIRST, reruns cannot call this. | ||
− | + | #Register Message Interceptor | |
− | + | @interceptor = Command.new(device_.devid_, -1000, 1, 5, 37) | |
− | + | @interceptor.params_[2] = device_.devid_.to_s | |
− | + | SendCommand(@interceptor) | |
− | + | ||
− | + | ||
− | + | ||
− | + | #Get the PLM Database | |
− | + | sendGetLink | |
− | + | #get Child devices | |
− | + | log('Finding Children..') | |
− | + | device_.childdevices_.each{|c| | |
− | + | if device_.childdevices_[c.to_s.to_i].devdata_[12].include? "Group" | |
+ | log('FOUND A GROUP') | ||
+ | else | ||
+ | $children[device_.childdevices_[c.to_s.to_i].devdata_[12].chomp.lstrip.rstrip] = c.to_s.to_i | ||
+ | end} | ||
+ | $children.keys.each{|c| log(c + ' = ' + $children[c].to_s) | ||
+ | } | ||
+ | log('reading stored Child configuration:') | ||
+ | |||
+ | $children.keys.each{|c| | ||
+ | #Get each Childs configuration | ||
+ | $state[$children[c]] = 0 | ||
+ | getdeviceconfig(c) # | ||
+ | |||
+ | #the above getdeviceconfig packs $configparams array | ||
+ | log('Configuration for ' + c + ' = ' + $configparams.inspect.to_s) | ||
+ | } | ||
+ | |||
+ | log('********************************************************') | ||
+ | #get childs actual configuation and status | ||
+ | $children.keys.each{|c| sendGetChildStatus(c)} | ||
+ | SndIns() | ||
− | |||
− | |||
− | |||
− | |||
end | end | ||
def mainRestart() | def mainRestart() | ||
− | + | #We have hashes already set up. | |
− | + | $childdatabases.each_key{|@insteonID| | |
− | + | $state[$children[@insteonID]] = 0 | |
− | + | sendGetChildStatus(@insteonID)} | |
+ | SndIns() | ||
end | end | ||
def setdeviceconfig(insteonid, configurestring) | def setdeviceconfig(insteonid, configurestring) | ||
− | + | @deviceid = $children[insteonid] | |
− | + | @cmdfrom = device_.devid_ | |
− | + | @cmdto = 4 #general info plugin | |
− | + | @priority = 1 | |
− | + | @type=1 #command | |
− | + | @cmdid = 246 | |
− | + | #set up command.. | |
− | + | @cmd = Command.new(@cmdfrom, @cmdto, @priority, @type, @cmdid) | |
− | + | @cmd.params_[2] = @deviceid.to_s | |
− | + | @cmd.params_[52] = '59' # Configuration | |
− | + | @cmd.params_[5] = configurestring | |
− | + | SendCommand(@cmd) | |
− | + | log('SetDeviceConfig:' + @cmd.to_s) | |
− | + | #log('SetDeviceConfig:' + configurestring) | |
+ | #log('Configuration Saved - will be available on next reload') | ||
end | end | ||
def getdeviceconfig(insteonid) | def getdeviceconfig(insteonid) | ||
− | + | @deviceid = $children[insteonid] | |
− | + | @configstring = '' | |
− | + | begin | |
− | + | @configstring = device_.childdevices_[@deviceid].devdata_[59].to_s | |
− | + | rescue | |
− | + | log('Device ID = ' + @deviceid.to_s) | |
− | + | log($red + 'Error - Child has no configuration'+ $grey) | |
− | + | log('Setting initial value of "****************"') | |
− | + | setdeviceconfig(insteonid, ('*' * 16)) | |
− | + | @configstring = '*' * 16 | |
− | + | sendPing(insteonid) | |
− | + | end | |
− | + | if @configstring == '' | |
− | + | $configparams = ['****************'] | |
− | + | log('CAUGHT BLANK RECORD') | |
− | + | setdeviceconfig(insteonid, ('*' * 16)) | |
− | + | sendPing(insteonid) | |
− | + | else | |
− | + | $configparams = @configstring.unpack('a16' * (@configstring.length / 16)) | |
− | + | $devicetemplate[insteonid] = getdevicetemplate($configparams[0][0..1], $configparams[0][2..3]) | |
− | + | end | |
− | + | #log($yellow + 'getdeviceconfig:' + $configparams.inspect + $grey) | |
− | + | #add the configuration parameters to the child database | |
− | + | $childdatabases[insteonid] = $configparams | |
− | + | #get the device type | |
end | end | ||
def sendGetLink() | def sendGetLink() | ||
− | + | #lets just see exactly what is in the PLM database | |
− | + | param = {'Command' => 'GetLnk'} | |
− | + | $cmdqueue << param | |
− | + | SndIns() | |
end | end | ||
def sendGetNext() | def sendGetNext() | ||
− | + | param = {'Command' => 'GetNext'} | |
− | + | if $wAIT == true | |
− | + | $cmdqueue.insert(1, param) | |
− | + | else | |
− | + | $cmdqueue.insert(0,param) | |
− | + | end | |
− | + | SndIns() | |
end | end | ||
def sendRemoteGetLink(insteonID) | def sendRemoteGetLink(insteonID) | ||
− | + | # Read First ALDB Record | |
− | + | # a few variables need to be set up here.. | |
− | + | $recordof = insteonID # save the insteon ID | |
− | + | insID = insteonID.chomp.split('.') # get the seperate bytes | |
− | + | $remoteDBOffsetMSB = 0x0F # initial offset | |
− | + | $remoteDBOffsetLSB = 0xF8 # initial LSB offset | |
− | + | param = {'Command' => 'SndIns', | |
− | + | 'Parameter1' => insID[0], #HB | |
− | + | 'Parameter2' => insID[1], #MB | |
− | + | 'Parameter3' => insID[2], #LB | |
− | + | 'Parameter4' => '0F', #Flags | |
− | + | 'Parameter5' => '28', #Cmd1 | |
− | + | 'Parameter6' => "%X" %$remoteDBOffsetMSB #Cmd2 Set MSB Offset | |
− | + | } | |
− | + | $cmdqueue << param | |
− | + | # repeat last param for each byte to read (F8..FF)=first record | |
− | + | for x in 0..7 | |
− | + | param = {'Command' => 'SndIns', | |
− | + | 'Parameter1' => insID[0], #HB | |
− | + | 'Parameter2' => insID[1], #MB | |
− | + | 'Parameter3' => insID[2], #LB | |
− | + | 'Parameter4' => '0F', #Flags | |
− | + | 'Parameter5' => '2B', #Cmd1 Peek | |
− | + | 'Parameter6' => "%X" %($remoteDBOffsetLSB + x) #Cmd2 | |
− | + | } | |
− | + | $cmdqueue << param | |
− | + | end | |
end | end | ||
def sendRemoteGetNext(insteonID) | def sendRemoteGetNext(insteonID) | ||
− | + | insID = insteonID.chomp.split('.') # get the seperate bytes | |
− | + | ### Do NOT forget to check to see if we need to decrease the MSB | |
− | + | if $remoteDBOffsetLSB == 0x00 | |
− | + | #OffsetMSB needs to be decreased, and LSB needs reset. | |
− | + | $remoteDBOffsetMSB = $remoteDBOffsetMSB - 1 | |
− | + | $remoteDBOffsetLSN = 0xFF # the next line will decrease this by 8 | |
− | + | end | |
− | + | # decrease DBOffsetLSB by 0x08 | |
− | + | $remoteDBOffsetLSB = $remoteDBOffsetLSB - 0x08 | |
− | + | for x in 0..7 | |
− | + | param = {'Command' => 'SndIns', | |
− | + | 'Parameter1' => insID[0], #HB | |
− | + | 'Parameter2' => insID[1], #MB | |
− | + | 'Parameter3' => insID[2], #LB | |
− | + | 'Parameter4' => '0F', #Flags | |
− | + | 'Parameter5' => '2B', #Cmd1 Peek | |
− | + | 'Parameter6' => "%X" %($remoteDBOffsetLSB + x) #Cmd2 | |
− | + | } | |
− | + | #log('sendRemoteGetNet:added to queue:' + param.inspect) | |
− | + | if $wAIT == true | |
− | + | $cmdqueue.insert(x + 1, param) | |
− | + | else | |
− | + | $cmdqueue.insert(x,param) | |
− | + | end | |
− | + | ||
− | + | end | |
end | end | ||
### Main command parsing routine is EZToDCE | ### Main command parsing routine is EZToDCE | ||
def EZToDCE(param) | def EZToDCE(param) | ||
− | + | #param contains a hash of EZBridge command structure | |
− | + | #log($blue + 'Queue:' + $cmdqueue[0].inspect + $grey) | |
− | + | #log($blue + 'Param:' + param.inspect + $grey) | |
− | + | #log($blue + 'currentcmd:' + $currentcmd.to_s + $grey) | |
− | + | #checkWait(param) | |
− | + | case param['Response'] | |
− | + | # Standard RESPONSES (to commands) | |
− | + | 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 | |
− | + | SndIns() | |
− | + | 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 | |
− | + | ### BUG FOUND ### When the EZBridge receives a command from an EXTERNAL source | |
− | + | ### ie not from this device, cmdqueue will be nil, and the code below | |
− | + | ### fails. Have to check against that. | |
− | + | if $cmdqueue.length > 0 | |
− | + | #First, check the response to make sure the command made it ok. | |
− | + | if param['Parameter9'].to_i == 6 #Ack received | |
− | + | #log('Sending to ProcessACK') | |
− | + | processACK(param) | |
− | + | else # NACK received - command failed. | |
− | + | log('Command NACKED') | |
− | + | end | |
− | + | else | |
− | + | #Response received for another device. | |
− | + | log('Response detected for a command that was not sent by me') | |
− | + | end | |
− | + | when 'SndX10' | |
− | + | log('Response detected for SndX10') | |
+ | if param['Parameter5'].to_i == 6 #ack | ||
+ | log('X10 Command Successfull') | ||
− | + | cmdComplete | |
+ | SndIns() | ||
+ | else | ||
+ | log('X10 Command FAILED') | ||
+ | cmdComplete | ||
+ | SndIns() | ||
− | + | end | |
+ | when 'StLnk' | ||
− | + | when 'CancelLnk' | |
− | + | when 'SetDev' | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | when 'RstPLM' | |
− | + | #Reset Response | |
− | + | $timeout = 1 | |
− | + | cmdComplete | |
− | + | SndIns() | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | when 'GetLnk' | |
− | + | if param['Parameter3'].to_i == 6 #ack | |
− | + | log('GetLnk ACKED') | |
− | + | #if we get this, we should get a AllLink Record Response next | |
− | + | else | |
− | + | log('GetLnk NACKED') | |
− | + | # The PLM is BLANK | |
− | + | #have to add records to the PLM here. | |
− | + | cmdComplete | |
+ | ### FINISHED WITH GetLnk | ||
+ | checkChildRecordsinPLM() | ||
+ | SndIns() | ||
+ | end | ||
+ | when 'GetNext' | ||
+ | if param['Parameter3'].to_i == 6 #ack | ||
+ | log('sendGetNext ACKED') | ||
+ | #if we get this, we should get a AllLink Record Response next | ||
+ | else | ||
+ | log('sendGetNext NACKED') | ||
+ | #we get this when there are no more records | ||
+ | cmdComplete | ||
+ | #FINISHED with GetNext | ||
+ | # if we are here, we are in config mode | ||
+ | # so, next is to check to make sure the | ||
+ | # childrens insteon ID is in the PLM | ||
+ | checkChildRecordsinPLM() | ||
+ | # now, to make sure that all the records in the PLM are sensed as children | ||
− | + | SndIns() | |
+ | end | ||
− | + | when 'SetCfg' # response from Setcfg command | |
+ | if param['Parameter4'].to_i == 6 #ack | ||
+ | log('SetCfg Completed') | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | else | ||
+ | log('SetCfg NACKED') | ||
+ | end | ||
+ | when 'GetLnkData' | ||
− | + | when 'LEDON' | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | when 'LEDOFF' | |
− | + | when 'MngLnk' | |
+ | if param['Parameter12'].to_i == 6 | ||
+ | log('MngLnk => ACK') | ||
+ | else | ||
+ | log('MngLnk => NACK') | ||
+ | end | ||
+ | cmdComplete | ||
+ | SndIns() | ||
− | + | 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 0x0 | |
+ | #log('REROUTING to processExternalCommand(param)') | ||
+ | processExternalCommand(param) | ||
+ | when 0x1 #Assign to Group | ||
+ | ### This is a broadcast message sent | ||
+ | # from a PING command | ||
+ | # or from a StartLink... | ||
+ | log('Caught Assign to Group Message from Device') | ||
+ | ### BUG HERE | ||
+ | #have to check flags to see if this is a broadcast message | ||
+ | log('Checking if this is a broadcast message') | ||
+ | log('Flags:' + param['Parameter9']) | ||
+ | if (param['Parameter9'].hex & 0x80) == 0x80 | ||
+ | log('Message IS BROADCAST') | ||
+ | #recvComplete | ||
+ | processDeviceInfo(param) | ||
− | + | # check to see if current cmd is for this broadcast.. | |
+ | log('Current Command:' + $cmdqueue[0]['Parameter5']) | ||
+ | if $cmdqueue[0]['Parameter5'] == '10' | ||
+ | #log('Clearing PING Command') | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | else | ||
+ | log('CURRENT CMD IS NOT PING - NOT CLEARING') | ||
+ | end | ||
− | + | else | |
− | + | log('Message is NOT Broadcast') | |
+ | end | ||
+ | when 0x2 #Delete from Group | ||
+ | when 0x10 # PING | ||
+ | #this is where I catch the InsStdMsg for ping. | ||
+ | log('Caught PING Message from Device') | ||
+ | $currentcmd = 1 | ||
− | + | when 0x11 # ON | |
− | + | log('Caught Insteon ON from INTERNAL source') | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
− | + | ||
− | + | ||
− | + | ||
− | + | insID = insHb + "." + insMb + "." + insLb | |
− | + | myDevFrom = $children[insID] | |
− | + | log('Current DIM level:' + param['Parameter11']) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | reportStatus(myDevFrom, hextopercent(param['Parameter11'])) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | $currentcmd = 0 | |
− | + | cmdComplete | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | SndIns() | |
− | + | when 0x13 # OFF | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
− | + | insID = insHb + "." + insMb + "." + insLb | |
− | + | myDevFrom = $children[insID] | |
− | + | reportStatus(myDevFrom, 0) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | $currentcmd = 0 | |
− | + | cmdComplete | |
− | + | #log('EVENT and state SENT!!!.48:[10]=0') | |
− | + | SndIns() | |
− | + | #####Thermostat Does Not report Status correctly Yet. Have to figure out reportStatus### | |
− | + | when 0x6A #Thermostat Control Get Zone Data (Temp, Setpoint,Humidity) | |
+ | log('Thermostat returned Zone Info: ' + param['Parameter11'].to_s) | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | #reportStatus(myDevFrom, hextopercent(param['Parameter11'])) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
− | + | when 0x6B #Thermostat Control Command Handle Response | |
− | + | log('Thermostat returned: ' + param['Parameter11'].to_s) | |
− | + | case param['Parameter11'].to_s | |
− | + | when '06' # ON/Auto | |
− | + | # $ThermostatStatus = 'ON/Auto' ##not used | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
− | + | insID = insHb + "." + insMb + "." + insLb | |
− | + | myDevFrom = $children[insID] | |
− | + | #log('Current Thermostat State:' + $ThermostatStatus) | |
− | + | #reportStatus(myDevFrom, 6) | |
− | + | $currentcmd = 0 | |
− | + | cmdComplete | |
− | + | SndIns() | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | when '09' #OFF | |
− | + | # $ThermostatStatus = 'OFF' ## not used may be for reportstatus | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
− | + | insID = insHb + "." + insMb + "." + insLb | |
− | + | myDevFrom = $children[insID] | |
− | + | #log('Current Thermostat State:' + $ThermostatStatus) | |
− | + | #reportStatus(myDevFrom, 9) | |
− | + | $currentcmd = 0 | |
− | + | cmdComplete | |
− | + | SndIns() | |
− | + | ||
− | + | when '04' # Heat | |
− | + | #$ThermostatStatus = 'HEAT' | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | #log('Current Thermostat State:' + $ThermostatStatus) | ||
+ | #reportStatus(myDevFrom, 4) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | |||
+ | when '05' # Cool | ||
+ | #$ThermostatStatus = 'COOL' | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | #log('Current Thermostat State:' + $ThermostatStatus) | ||
+ | #reportStatus(myDevFrom, 5) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | |||
+ | |||
+ | when '07' # Fan On | ||
+ | 2#$ThermostatStatus = 'COOL' | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | #log('Current Thermostat State:' + $ThermostatStatus) | ||
+ | #reportStatus(myDevFrom, 5) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | |||
+ | |||
+ | when '08' # Fan Off | ||
+ | #$ThermostatStatus = 'COOL' | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | #log('Current Thermostat State:' + $ThermostatStatus) | ||
+ | #reportStatus(myDevFrom, 5) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | end | ||
+ | |||
+ | |||
+ | when 0x6C #Thermostat Control Get Zone Cool Point Data | ||
+ | log('Thermostat returned Zone Info: ' + param['Parameter11'].to_s) | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | log('Current Zone level:' + param['Parameter11'].to_s) | ||
+ | #reportStatus(myDevFrom, hextopercent(param['Parameter11'])) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | |||
+ | when 0x6D #Thermostat Control Get Zone Heat Point Data | ||
+ | log('Thermostat returned Zone Info: ' + param['Parameter11'].to_s) | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | log('Current Zone level:' + param['Parameter11'].to_s) | ||
+ | #reportStatus(myDevFrom, hextopercent(param['Parameter11'])) | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | |||
+ | |||
+ | when 0x19 # Status Report | ||
+ | # now to clear the currentcmd and remove command from the queue | ||
+ | $currentcmd = 0 | ||
+ | cmdComplete | ||
+ | |||
+ | log('Processing 0x19 Status Report') | ||
+ | #This is where I get the database delta (in cmd1) | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | #First, to compare the DB Delta with current config. | ||
+ | #Database Delta... | ||
+ | delta = param['Parameter10'].to_s | ||
+ | log($blue + 'Database Delta=' + delta + $grey) | ||
+ | log($blue + 'Configuration is:' + getdeltafromconfig(insID) + $grey) | ||
+ | if delta == getdeltafromconfig(insID) | ||
+ | if $children[insID] != nil | ||
+ | myDevFrom = $children[insID] | ||
+ | myDevTo = -1000 #DCE Router | ||
+ | myPriority = 1 | ||
+ | myType = 2 #Event | ||
+ | |||
+ | #Send an EVENT to report STATE ONLY if database has not changed | ||
+ | # AND child exists in pluto | ||
+ | reportStatus(myDevFrom, hextopercent(param['Parameter11'])) | ||
+ | end | ||
+ | else | ||
+ | log('Databse CHANGED -getting remote database') | ||
+ | #here, I have to WIPE the databse | ||
+ | # to prepare it for new data | ||
+ | ### here is where the DAMN CONFIG was reset!!! | ||
+ | oldconfigstring = $childdatabases[insID][0] | ||
+ | $childdatabases[insID] = [oldconfigstring] | ||
+ | log('Setting Database Config') | ||
+ | $childdatabases[insID][0][6..7] = delta | ||
+ | savechilddatabases(insID) | ||
+ | sendRemoteGetLink(insID) | ||
+ | end | ||
+ | # finally, to check execute next command... | ||
+ | SndIns() | ||
+ | when 0x28 # Set Address MSB | ||
+ | log('Received SET Address MSB from remote device') | ||
+ | $currentcmd = 0 | ||
+ | $remoteLinkRecord = '' | ||
+ | cmdComplete | ||
+ | SndIns() | ||
+ | when 0x2B # peek | ||
+ | ### BUG HERE... have to verify response is a PEEK command | ||
+ | #response command is stored in parameter10 | ||
+ | if param['Parameter10'].hex == 0x2B # this is the peek command | ||
+ | cmdComplete | ||
+ | log('Received PEEK from remote Device! DATA=' + param['Parameter11']) | ||
+ | checkPeekData(param) | ||
+ | $currentcmd = 0 | ||
+ | SndIns() | ||
+ | else | ||
+ | log('Waiting for remote PEEK response, but got :' + param['Parameter10']) | ||
+ | end | ||
+ | else | ||
+ | end | ||
+ | |||
+ | when 'X10Msg' | ||
+ | log($purple + 'X10 Message Received' + $grey) | ||
+ | if param['Parameter4'].hex == 0x00 | ||
+ | log('This byte is a House/Unit Code') | ||
+ | hn = param['Parameter3'][0].chr | ||
+ | ln = param['Parameter3'][1].chr | ||
+ | $x10byte1 = $X10HouseCodes[hn] | ||
+ | $x10byte1 += $X10UnitCodes[ln] | ||
+ | log('Translated X10 House/Unit Code:' + $x10byte1) | ||
+ | else | ||
+ | log('This byte is a House/Command Code') | ||
+ | hn = param['Parameter3'][0].chr | ||
+ | ln = param['Parameter3'][1].chr | ||
+ | $x10byte2 = $X10HouseCodes[hn] | ||
+ | $x10byte2 += $X10CommandCodes[ln] | ||
+ | log('Translated X10 Command Code:' + $x10byte2) | ||
+ | log('X10 Command ready to send:' + $x10byte1 + ' ' + $x10byte2) | ||
+ | case $X10CommandCodes[ln] | ||
+ | when 'On' | ||
+ | #Send ON to lmnce | ||
+ | if $children[$x10byte1] == nil | ||
+ | log('I do not control this X10 device') | ||
+ | else | ||
+ | cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 192) | ||
+ | cmd.params_[120] = "1" | ||
+ | SendCommand(cmd) | ||
+ | end | ||
+ | when 'Off' | ||
+ | #Send OFF to lmnce | ||
+ | if $children[$x10byte1] == nil | ||
+ | log('I do not control this X10 device') | ||
+ | else | ||
+ | cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 193) | ||
+ | cmd.params_[120] = "1" | ||
+ | SendCommand(cmd) | ||
+ | end | ||
+ | when 'Bright' | ||
+ | if $children[$x10byte1] == nil | ||
+ | log('I do not control this X10 device') | ||
+ | else | ||
+ | #send a command to set the state + 1 | ||
+ | @curstate = ($state[$x10byte1] / 100) * 32 #get equal 32 steps | ||
+ | $state[$x10byte1] = ((@curstate + 1) / 32) * 100 | ||
+ | cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 184) | ||
+ | cmd.params_[76] = $state[$x10byte1].to_s | ||
+ | cmd.params_[120] = "1" | ||
+ | SendCommand(cmd) | ||
+ | #$state[$x10byte1] = ($state[$x10byte1] / 100) * 32 | ||
+ | end | ||
+ | when 'Dim' | ||
+ | @curstate = ($state[$x10byte1] / 100) * 32 #get equal 32 steps | ||
+ | $state[$x10byte1] = ((@curstate - 1) / 32) * 100 | ||
+ | cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 184) | ||
+ | cmd.params_[76] = $state[$x10byte1].to_s | ||
+ | cmd.params_[120] = "1" | ||
+ | SendCommand(cmd) | ||
+ | when 'All Lights Off' | ||
+ | log('ALL Lights OFF Command not implemented') | ||
+ | when 'All Lights On' | ||
+ | log('All Lights ON Command not implemented') | ||
+ | when 'Status Request' | ||
+ | log('Status Request Command not implemented') | ||
+ | when 'Hail Ack' | ||
+ | log('Hail Ack Command not implemented') | ||
+ | end | ||
+ | |||
+ | end | ||
+ | when 'InsLnkSts' | ||
+ | log('InsLnkSts Received') | ||
+ | |||
+ | when 'BtnRpt' | ||
+ | log('Button Report Received') | ||
+ | when 'UsrRst' | ||
+ | log('User Reset Response Received') | ||
+ | when 'GrpEvntRpt' | ||
+ | log('Group Event Report Received') | ||
+ | |||
+ | when 'LnkData' | ||
+ | processLnkData(param) | ||
+ | # Other messages | ||
+ | when 'PLMTimeout' | ||
+ | log('PLM Timeout detected.. resetting EZBridge') | ||
+ | resetcmd = {'Command' => 'Reset'} | ||
+ | if $wAIT == true | ||
+ | $cmdqueue.insert(1, resetcmd) | ||
+ | else | ||
+ | $cmdqueue.insert(0,resetcmd) | ||
+ | end | ||
+ | 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'} | ||
+ | if $wAIT == true | ||
+ | $cmdqueue.insert(1, resetcmd) | ||
+ | else | ||
+ | $cmdqueue.insert(0,resetcmd) | ||
+ | end | ||
+ | |||
+ | sleep 15 | ||
+ | $wAIT = false | ||
+ | SndIns() | ||
+ | when 'LongAck' | ||
+ | log('-----XXXXXXX' + param['Response']) | ||
+ | # Error - seems to show up after PLMEchoError | ||
+ | resetcmd = {'Command' => 'Reset'} | ||
+ | if $wAIT == true | ||
+ | $cmdqueue.insert(1, resetcmd) | ||
+ | else | ||
+ | $cmdqueue.insert(0,resetcmd) | ||
+ | end | ||
+ | sleep 15 | ||
+ | $wAIT = false | ||
+ | SndIns() | ||
+ | else | ||
+ | log('-----XXXXXXX UNKNOWN Response Received') | ||
+ | end | ||
end | end | ||
Line 577: | Line 753: | ||
### Support routine for EZToDCE | ### Support routine for EZToDCE | ||
def processLnkData(param) | def processLnkData(param) | ||
− | + | #Caught a LnkData Response | |
− | + | log('LnkData Message Received') | |
− | + | log(param.inspect) | |
− | + | if param['Parameter6'] == '00' and param['Parameter7'] == '00' | |
− | + | log('FOUND X10 DEVICE!!!') | |
− | + | insteonID = padhex(param['Parameter5']) | |
− | + | else | |
− | + | insteonID = padhex(param['Parameter5']) + '.' + padhex(param['Parameter6']) + '.' + padhex(param['Parameter7']) | |
− | + | end | |
− | + | group = param['Parameter4'] | |
− | + | recflags = param['Parameter3'] | |
− | + | lnkdata1 = param['Parameter8'] | |
+ | lnkdata2 = param['Parameter9'] | ||
+ | lnkdata3 = param['Parameter10'] | ||
+ | #pack string to store for PLM Database | ||
+ | @currentrecord = recflags + group | ||
+ | @currentrecord += param['Parameter5'] + param['Parameter6'] + param['Parameter7'] | ||
+ | @currentrecord += lnkdata1 + lnkdata2 + lnkdata3 | ||
− | + | #Add to plmdatabase | |
− | + | $plmdatabase << @currentrecord | |
− | + | log('record Flags:' + recflags) | |
− | + | #log('PLM database=' +$plmdatabase.inspect) | |
− | + | if (recflags[0] & 0x80) == 0x80 # Record is in use if true | |
− | + | end | |
− | + | if (recflags[0] & 0x40) == 0x40 # Controller if true | |
− | + | log('Controller') | |
− | + | else | |
− | + | log('Responder') | |
+ | end | ||
− | + | log('Insteon ID:' + insteonID + ', Group:' + group) | |
− | + | cmdComplete | |
− | + | sendGetNext() | |
end | end | ||
### Support Routine for EZToDCE | ### Support Routine for EZToDCE | ||
def processExternalCommand(param) | def processExternalCommand(param) | ||
− | + | #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 | |
− | + | ### have to check here if child is mine! | |
− | + | # This is where I have to check for a broadcast command.. | |
− | + | #if so, search the child databases for responders, | |
− | + | #and fire events for each responder. | |
− | + | #Message flag is in parameter9 Group command 0xCx (All-Link Broadcast Message Pg 42.) | |
− | + | #Group is in parameter8 | |
− | + | #From InsteonID is parameters 3, 4, 5 | |
− | + | if (param['Parameter9'].hex & 0xC0) == 0xC0 # Message is Broadcast | |
− | + | log('Rerouting to processBroadcastMessage') | |
− | + | processBroadcastMessage(param) | |
− | + | else | |
− | + | log('Process External Command:') | |
− | + | log('Param:' + param.inspect) | |
− | + | # there is no ack here. Simply Send COMMANDS back to DCE | |
− | + | # and Complete the recv.. | |
− | + | case param['Parameter10'].hex #this is the command | |
− | + | when 0x01 #Assign to Group | |
− | + | log('Caught EXTERNAL Assign to Group') | |
− | + | processDeviceInfo(param) | |
− | + | recvComplete | |
− | + | when 0x02 #Delete from Group | |
− | + | when 0x02 #Delete from Group | |
− | + | log('Caught EXTERNAL Delete from Group') | |
− | + | recvComplete | |
− | + | when 0x10 # PING | |
− | + | log('Caught EXTERNAL Insteon PING result') | |
+ | recvComplete | ||
− | + | when 0x11 #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 | |
− | + | log('From:' +insID) | |
− | + | log('Device:' + $children[insID].to_s) | |
− | + | myDevFrom = $children[insID] | |
− | + | # check to see if I own child | |
− | + | if myDevFrom == nil | |
− | + | log('I do not control this device.') | |
− | + | else | |
− | + | reportStatus(myDevFrom, hextopercent(param['Parameter11'])) | |
− | + | $currentcmd = 0 | |
− | + | end | |
− | + | recvComplete | |
− | + | when 0x13 #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] | |
− | + | if myDevFrom == nil | |
− | + | log('I do not control this device.') | |
− | + | else | |
− | + | reportStatus(myDevFrom, 0) | |
− | + | $currentcmd = 0 | |
− | + | #log('EVENT and state SENT!!!.48:[10]=0') | |
− | + | end | |
− | + | recvComplete | |
− | + | ||
− | + | when 0x6A #Thermostat Zone Command | |
− | + | log('Caught EXTERNAL Insteon Thermostat result') | |
− | + | #on level is in cmd2 | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
− | + | insID = insHb + "." + insMb + "." + insLb | |
− | + | myDevFrom = $children[insID] | |
− | + | if myDevFrom == nil | |
− | + | log('I do not control this device.') | |
− | + | else | |
− | + | #case param['Parameter11'].to_s | |
+ | #when '00' | ||
+ | reportStatus(myDevFrom, hextoTempurature(param['Parameter11'])) | ||
+ | $currentcmd = 0 | ||
+ | #when '60' #humidity | ||
+ | #when '20'#setpoint | ||
+ | #log('EVENT and state SENT!!!.48:[10]=0') | ||
+ | end | ||
+ | |||
+ | when 0x6B #Thermostat Mode Command | ||
+ | log('Caught EXTERNAL Insteon Thermostat result') | ||
+ | #on level is in cmd2 ie( HEAT(0x04), COOL(0x05), or AUTO(0x06)) | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | if myDevFrom == nil | ||
+ | log('I do not control this device.') | ||
+ | else | ||
+ | #reportStatus(myDevFrom, 0) | ||
+ | $currentcmd = 0 | ||
+ | #log('EVENT and state SENT!!!.48:[10]=0') | ||
+ | end | ||
+ | |||
+ | when 0x6C #Thermostat Zone Cool Command | ||
+ | log('Caught EXTERNAL Insteon Thermostat result') | ||
+ | #on level is in cmd2 | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | if myDevFrom == nil | ||
+ | log('I do not control this device.') | ||
+ | else | ||
+ | reportStatus(myDevFrom, hextoTempurature(param['Parameter11'])) | ||
+ | $currentcmd = 0 | ||
+ | #log('EVENT and state SENT!!!.48:[10]=0') | ||
+ | end | ||
+ | |||
+ | when 0x6D #Thermostat Zone Heat Command | ||
+ | log('Caught EXTERNAL Insteon Thermostat result') | ||
+ | #on level is in cmd2 | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
+ | insID = insHb + "." + insMb + "." + insLb | ||
+ | myDevFrom = $children[insID] | ||
+ | if myDevFrom == nil | ||
+ | log('I do not control this device.') | ||
+ | else | ||
+ | reportStatus(myDevFrom, hextoTempurature(param['Parameter11'])) | ||
+ | $currentcmd = 0 | ||
+ | #log('EVENT and state SENT!!!.48:[10]=0') | ||
+ | end | ||
+ | |||
+ | |||
+ | |||
+ | when 0x15; log('Caught EXTERNAL Insteon Brighten Result') | ||
+ | when 0x16; log('Caught EXTERNAL Insteon DIM Result') | ||
+ | when 0x24; log('Caught EXTERNAL Insteon DO EE READ') | ||
+ | when 0x28; log('Caught EXTERNAL Insteon SET ADDRESS MSB') | ||
+ | when 0x29; log('Caught EXTERNAL Insteon POKE') | ||
+ | when 0x2A; log('Caught EXTERNAL Insteon POKE EXTENDED') | ||
+ | when 0x2B; log('Caught EXTERNAL Insteon PEEK') | ||
+ | when 0x2C; log('Caught EXTERNAL Insteon PEEK INTERNAL') | ||
+ | when 0x2D; log('Caught EXTERNAL Insteon POKE INTERNAL') | ||
+ | else | ||
+ | log('Unknown EXTERNAL Insteon Command.') | ||
+ | end | ||
+ | end | ||
end | end | ||
### Support Routine for EZToDCE | ### Support Routine for EZToDCE | ||
def processACK(param) | def processACK(param) | ||
− | + | #log('In ProcessACK: Param7:' + param['Parameter7']) | |
− | + | #log('CurrentCmd=' + $currentcmd.to_s) | |
− | + | case param['Parameter7'].hex #Received an ack to THIS command | |
− | + | when 0x1 #Assign to Group | |
− | + | log('Got Assign to Group ACK') | |
− | + | $currentcmd = 0x01 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | #processDeviceInfo(param) | |
− | + | #cmdComplete | |
− | + | when 0x2 #Delete from Group | |
− | + | when 0x10 # PING | |
− | + | log('Got PING ACK') | |
− | + | #cmdComplete | |
− | + | $currentcmd = 0x1 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x11 #ON | |
− | + | $currentcmd = 0x11 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x13 #OFF | |
− | + | $currentcmd = 0x13 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x6A #Thermostat Zone Command | |
− | + | $currentcmd = 0x6A | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x6B #Thermostat Control Command | |
− | + | $currentcmd = 0x6B | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x6C #Thermostat Cool Command | |
− | + | $currentcmd = 0x6C | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x6D #Thermostat Cool Command | |
− | + | $currentcmd = 0x6D | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x15 #Bright | |
− | + | $currentcmd = 0x15 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x16 #DIM | |
− | + | $currentcmd = 0x16 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x17 #Start Manual Change | |
− | + | when 0x18 #Stop Manual Change | |
− | + | when 0x19 #Status Request | |
− | + | # Status Request Acked - get ready for InsStdMsg | |
− | + | $currentcmd = 0x19 | |
− | + | # change cmd to reflect InsStdMsg | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x24 | |
− | + | log('Caught ACK for Insteon DO EE READ') | |
− | + | $currentcmd = 0x24 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | when 0x28 | |
− | + | log('Caught ACK for Insteon SET ADDRESS MSB') | |
− | + | $currentcmd = 0x28 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | ||
− | + | when 0x29 | |
− | + | log('Caught ACK for Insteon POKE') | |
− | + | $currentcmd = 0x29 | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | ||
− | + | when 0x2A | |
− | + | log('Caught ACK for Insteon POKE EXTENDED') | |
− | + | $currentcmd = 0x2A | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | ||
− | + | when 0x2B | |
− | + | #log('Caught ACK for Insteon PEEK') | |
− | + | $currentcmd = 0x2B | |
− | + | $cmdqueue[0]['Command'] = 'InsStdMsg' | |
− | + | ||
− | + | when 0x2C | |
+ | log('Caught ACK for Insteon PEEK INTERNAL') | ||
+ | $currentcmd = 0x2C | ||
+ | $cmdqueue[0]['Command'] = 'InsStdMsg' | ||
+ | |||
+ | when 0x2D | ||
+ | log('Caught ACK for Insteon POKE INTERNAL') | ||
+ | $currentcmd = 0x2D | ||
+ | $cmdqueue[0]['Command'] = 'InsStdMsg' | ||
+ | |||
+ | else | ||
+ | log('Unknown Insteon Cmd1') | ||
+ | end | ||
end | end | ||
Line 775: | Line 1,042: | ||
def checkPeekData(param) | def checkPeekData(param) | ||
− | + | $remoteLinkRecord += param['Parameter11'].hex.chr | |
− | + | log('CURRENT REMOTE RECORD IS:') | |
− | + | debug($remoteLinkRecord) | |
− | + | if $remoteLinkRecord.length == 8 | |
− | + | log('REMOTE RECORD COMPLETE!') | |
− | + | processRemoteRecord(param) | |
− | + | $remoteLinkRecord = '' | |
− | + | end | |
end | end | ||
def processRemoteRecord(param) | def processRemoteRecord(param) | ||
− | + | #have to find MY address | |
− | + | insHb = param['Parameter3'] # From | |
− | + | insMb = param['Parameter4'] | |
− | + | insLb = param['Parameter5'] | |
− | + | insID = padhex(insHb) + "." + padhex(insMb) + "." + padhex(insLb) | |
− | + | log('Processing remote Record below:') | |
− | + | @flags = "\nFrom Device:" + insID + "\nFlags:\n" | |
− | + | if ($remoteLinkRecord[0] & 0x02) == 0x02 # High water mark | |
− | + | @flags += "Not the last record\n" | |
− | + | else | |
− | + | @flags += "This IS the last record\n" | |
− | + | end | |
− | + | if ($remoteLinkRecord[0] & 0x80) == 0x80 # Record is in use | |
− | + | @flags += "Record In Use\n" | |
− | + | if ($remoteLinkRecord[0] & 0x40) == 0x40 # Controller/Responder | |
− | + | @flags += "I am a Controller of " | |
− | + | else | |
− | + | @flags += "I am a Responder of " | |
− | + | end | |
− | + | @insteonID = padhex("%X" %$remoteLinkRecord[2]) + '.' | |
− | + | @insteonID += padhex("%X" %$remoteLinkRecord[3]) + '.' | |
− | + | @insteonID += padhex("%X" %$remoteLinkRecord[4]) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | @group = "%X" %$remoteLinkRecord[1] | |
− | + | @flags += @insteonID + " Group:" + @group | |
− | + | @work = padhex("%X" %$remoteLinkRecord[0]) #Control byte | |
− | + | @work += padhex("%X" %$remoteLinkRecord[1]) # Group | |
− | + | @work += padhex("%X" %$remoteLinkRecord[2]) # ID HB | |
− | + | @work += padhex("%X" %$remoteLinkRecord[3]) # ID MB | |
− | + | @work += padhex("%X" %$remoteLinkRecord[4]) # ID LB | |
− | + | @work += padhex("%X" %$remoteLinkRecord[5]) # Data1 | |
− | + | @work += padhex("%X" %$remoteLinkRecord[6]) # Data2 | |
+ | @work += padhex("%X" %$remoteLinkRecord[7]) # Data3 | ||
+ | log('adding to:' + insID) | ||
+ | log('Value:' + @work) | ||
+ | $childdatabases[insID] << @work #add it to the database | ||
+ | # log('Current Database:' + $childdatabases.inspect) | ||
+ | #now to save the database to configuration. | ||
+ | savechilddatabases(insID) | ||
+ | # Now to check to see if the child exists as a record | ||
+ | if $childdatabases[@insteonID] == nil | ||
+ | log('InsteonID is NEW, adding Child database entry') | ||
+ | $childdatabases[@insteonID] = ['****************'] | ||
+ | $rerun = true | ||
+ | sendAddtoPLM(@insteonID) | ||
+ | sendPing(@insteonID) | ||
+ | else | ||
+ | log('InsteonID:' + @insteonID.to_s + 'seems to exist in child databases') | ||
+ | log('CDB:' + $childdatabases.inspect) | ||
+ | |||
+ | end | ||
+ | else | ||
+ | @flags += "Record NOT in use\n" | ||
+ | end | ||
+ | log($aqua + @flags + $grey) | ||
+ | log2(@flags) | ||
+ | if ($remoteLinkRecord[0] & 0x02) == 0x02 | ||
+ | sendRemoteGetNext(insID) | ||
+ | end | ||
end | end | ||
def savechilddatabases(insteonID) | def savechilddatabases(insteonID) | ||
− | + | #This takes the $childdatabase hash+array and encodes it to | |
− | + | # save it as a string. | |
− | + | @work = '' | |
− | + | #log($yellow + 'SaveChildDatabases::nitems:' + $childdatabases[insteonID].nitems.to_s) | |
− | + | #log($childdatabases[insteonID].inspect + $grey) | |
− | + | $childdatabases[insteonID].each{|record| | |
− | + | @work += record | |
− | + | } | |
− | + | #now to save the string... | |
− | + | setdeviceconfig(insteonID, @work) | |
end | end | ||
def sendPing(insteonID) | def sendPing(insteonID) | ||
− | + | insID = insteonID.split('.') | |
− | + | param = {'Command' => 'SndIns', | |
− | + | 'Parameter1' => insID[0], | |
− | + | 'Parameter2' => insID[1], | |
− | + | 'Parameter3' => insID[2], | |
− | + | 'Parameter4' => '0F', | |
− | + | 'Parameter5' => '10', #ID Request | |
− | + | 'Parameter6' => '00'} | |
− | + | $cmdqueue << param | |
− | + | log('PING Sent!') | |
end | end | ||
− | def | + | def getdevicetemplate(cat, subcat) |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | log('Entered getdevicetemplate, Cat=' + cat.to_s + ', subcat = ' + subcat.to_s) | |
− | + | @templid = 0 | |
− | + | case cat.hex | |
− | + | when 0x0 # Generalized Controllers | |
− | + | case subcat.hex | |
− | + | when 0x04; log('Found ControLinc [2430]') | |
− | + | when 0x05; log('Found RemoteLinc [2440]') | |
− | + | when 0x06; log('Found Icon Tabletop Controller [2830]') | |
− | + | when 0x09; log('Found SignaLinc RF Signal Enhancer [2442]') | |
− | + | when 0x0A; log('Found Balboa Instruments Poolux LCD Controller') | |
− | + | when 0x0B; log('Found Access Point [2443]') | |
− | + | when 0x0C; log('Found IES Color Touchscreen') | |
− | + | end | |
− | + | when 0x01 # Dimmable Lighting Control | |
− | + | # all these devices are associated with Template 38 | |
− | + | # Light Switch (dimmable) | |
− | + | @templid = 38 | |
− | + | case subcat.hex | |
− | + | when 0x00; log('Found LampLinc V2 [2456D3]') | |
− | + | when 0x01; log('Found SwitchLinc V2 Dimmer 600W [2476D]') | |
− | + | when 0x02; log('Found In-LineLinc Dimmer [2475D]') | |
− | + | when 0x03; log('Found Icon Switch Dimmer [2876D]') | |
− | + | when 0x04; log('Found SwitchLinc V2 Dimmer 1000W [2476DH]') | |
− | + | when 0x06; log('Found LampLinc 2-pin [2456D2]') | |
− | + | when 0x07; log('Found Icon LampLinc V2 2-pin [2456D2]') | |
− | + | when 0x09; log('Found KeypadLinc Dimmer [2486D]') | |
− | + | when 0x0A; log('Found Icon In-Wall Controller [2886D]') | |
− | + | when 0x0D; log('Found SocketLinc [2454D]') | |
− | + | when 0x13; log('Found Icon SwitchLinc Dimmer for Lixar/Bell Canada [2676D-B]') | |
− | + | when 0x17; log('Found ToggleLinc Dimmer [2466D]') | |
− | + | end | |
− | + | when 0x02 # Switched Lighting Control | |
− | + | # all these devices are associated with Template 37 | |
− | + | # Light Switch (ON/OFF) | |
− | + | @templid = 37 | |
− | + | case subcat.hex | |
− | + | ||
− | + | when 0x09; log('Found ApplianceLinc [2456S3]') | |
− | + | when 0x0A; log('Found SwitchLinc Relay [2476S]') | |
− | + | when 0x0B; log('Found Icon On Off Switch [2876S]') | |
− | + | when 0x0C; log('Found Icon Appliance Adapter [2856S3]') | |
− | + | when 0x0D; log('Found ToggleLinc Relay [2466S]') | |
− | + | when 0x0E; log('Found Switchlinc Relay Countdown Timer [2476ST]') | |
− | + | when 0x10; log('Found In-LineLinc Relay [2475D]') | |
− | + | when 0x13; log('Found Icon SwitchLinc Relay for Lixar/Bell Canada [2676R-B]') | |
− | + | end | |
− | + | when 0x03 # Network Bridges | |
− | + | case subcat.hex | |
− | + | when 0x01; log('Found PowerLinc Serial [2414S]') | |
− | + | when 0x02; log('Found PowerLinc USB [2414U]') | |
− | + | when 0x03; log('Found Icon PowerLinc Serial [2814S]') | |
− | + | when 0x04; log('Found Icon PowerLinc USB [2814U]') | |
− | + | when 0x05; log('Found Smartlabs Power Line Modem Serial [2412S]') | |
− | + | end | |
− | + | when 0x04 # Irrigation Control | |
− | + | # all these devices are associated with Template 1780 | |
− | + | # Standard Irrigation Sprinkler | |
− | + | @templid = 1780 | |
− | + | case subcat.hex | |
− | + | ||
− | + | when 0x00; log('Found Simplehomenet EZRain1 Sprinkler Controller') | |
− | + | end | |
− | + | when 0x05 # Climate Control | |
− | + | case subcat.hex | |
− | + | when 0x00; log('Found Broan SMSC080 Exhaust Fan') | |
− | + | when 0x01; log('Found Simplehomenet EZTherm') | |
+ | when 0x02; log('Found Broan SMSC110 Exhaust Fan') | ||
+ | when 0x03 | ||
+ | log('Found Venstar RF Thermostat Module') | ||
+ | @templid = 2198 #Set Template | ||
+ | when 0x04; log('Found Simplehomenet EZStat Thermostat') | ||
+ | end | ||
+ | when 0x06 # Pool and Spa Control | ||
+ | case subcat.hex | ||
+ | when 0x00; log('Found Simplehomenet EZPool') | ||
+ | end | ||
+ | when 0x07 # Sensors and Actuators | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x08 # Home Entertainment | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x09 # Energy Management | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x0A # Built-In Appliance Control | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x0B # Plumbing | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x0C # Communication | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x0D # Computer Control | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x0E # Window Coverings | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x0F # Access Control | ||
+ | case subcat.hex | ||
+ | when 0x00 | ||
+ | end | ||
+ | when 0x10 # Security, Health, and Safety | ||
+ | when 0x11 # Surveillance | ||
+ | when 0x12 # Automotive | ||
+ | when 0x13 # Pet care | ||
+ | when 0x14 # Toys | ||
+ | when 0x15 # Timekeeping | ||
+ | when 0x16 # Holiday | ||
+ | end | ||
+ | return @templid | ||
+ | end | ||
+ | |||
+ | def processDeviceInfo(param) | ||
+ | ### temporary | ||
+ | ### 12-24-07 Adding Device Template compatibility.. | ||
+ | #have to find MY address | ||
+ | insHb = param['Parameter3'] # From | ||
+ | insMb = param['Parameter4'] | ||
+ | insLb = param['Parameter5'] | ||
− | + | insID = padhex(insHb) + "." + padhex(insMb) + "." + padhex(insLb) | |
− | + | #set the devicecat and device subcat in the childdatabases | |
− | + | # 0-1 Device Category | |
− | + | # 2-3 Device SubCategory | |
− | + | # 4-5 Device Firmware | |
− | + | log('proccessDeviceInfo:Insteon ID' + insID) | |
− | + | $childdatabases[insID][0][0..1] = param['Parameter6'] | |
− | + | $childdatabases[insID][0][2..3] = param['Parameter7'] | |
− | + | $childdatabases[insID][0][4..5] = param['Parameter8'] | |
− | + | savechilddatabases(insID) | |
− | + | log('InsteonID: ' + insID) | |
− | + | #log('Child Config AFTER update:' + $childdatabases[insID][0].to_s) | |
− | + | log($yellow) | |
− | + | @template = getdevicetemplate(param['Parameter6'], param['Parameter7']) | |
− | + | $devicetemplate[insID] = @template | |
− | + | log('Template ID:' + @template.to_s) | |
− | + | ### eventually, open a XML configuration script? | |
− | + | ### or read saved data from mysql? | |
− | + | ### most likely save this information to sql with device. | |
− | + | ### eventually, IPKDB will be available to ping. | |
− | + | log('for Insteon ID:' + insID) | |
− | + | log($grey) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
end | end | ||
def recvComplete | def recvComplete | ||
− | + | # Clears the wait flag, but does not remove a command from the queue | |
− | + | $wAIT = false | |
− | + | log($green + "Receive Completed. Checking command queue" + $grey) | |
− | + | if $cmdqueue.nitems > 0 then | |
− | + | log("Queue:" + $aqua + $cmdqueue.nitems.to_s + $grey + " : executing next command") | |
− | + | SndIns() | |
− | + | else | |
− | + | log($yellow + 'Queue Empty.' + $grey) | |
− | + | if $rerun == true | |
− | + | log('RERUN=TRUE, RESTARTING') | |
− | + | $rerun = false | |
− | + | mainRestart() | |
− | + | else | |
− | + | log('RERUN Not needed. Checking if reported..') | |
− | + | #report Child devices here. | |
− | + | if $reported == false | |
− | + | log('Reporting Child Devices') | |
− | + | @work = "" | |
− | + | $childdatabases.each_key{ | |
− | + | |insteonID| | |
− | + | log('Child:' + insteonID) | |
+ | log('Config:' + $childdatabases[insteonID].inspect) | ||
+ | @template = $devicetemplate[insteonID] | ||
+ | @work += insteonID + "\t\t\t" + @template.to_s + "\t\n" | ||
+ | } | ||
+ | log(@work) | ||
+ | cmd = Command.new(device_.devid_, -1001, 1, 2, 54) | ||
+ | cmd.params_[13] = @work | ||
+ | SendCommand(cmd) | ||
− | + | $reported = true | |
+ | else | ||
+ | log('report not needed') | ||
+ | end | ||
+ | end | ||
+ | |||
+ | end | ||
+ | end | ||
+ | def removecurrentcommand | ||
+ | #get the current child | ||
+ | log('in RemoveCurrentCommand') | ||
+ | log('Current Command:' + $cmdqueue[0].inspect) | ||
+ | #id is in param123 | ||
+ | @id = $cmdqueue[0]['Parameter1'] | ||
+ | @id += '.' + $cmdqueue[0]['Parameter2'] | ||
+ | @id += '.' + $cmdqueue[0]['Parameter3'] | ||
+ | log('ID=' + @id) | ||
+ | #now to remove from child and PLM databases | ||
+ | removefromchild(@id) | ||
+ | removefromplm(@id) | ||
+ | cmdComplete | ||
end | end | ||
def cmdComplete | def cmdComplete | ||
− | + | # Clears the wait flag, and removes the command from the queue. | |
− | + | $wAIT = false | |
− | + | $resetNext = 0 | |
− | + | $cmdqueue.delete_at(0) | |
− | + | # now that THAT command is completed, check to see if there is | |
− | + | # another command ready to transmit. | |
− | + | log($green + "Command Completed." + $grey) | |
end | end | ||
def checkWait(param) | def checkWait(param) | ||
− | + | #Checks for response from current command. | |
− | + | if $cmdqueue[0] != nil | |
− | + | if $wAIT == true | |
− | + | #log('CW:waiting for command to complete') | |
− | + | else | |
− | + | #log('CW:reports clear') | |
− | + | end | |
− | + | else | |
− | + | log('------:)----checkWait: command queue is emtpy') | |
− | + | if $wAIT == true #this should never happen | |
− | + | log('------:(XXX-CheckWait: TRUE') | |
− | + | end | |
− | + | end | |
end | end | ||
def plmparse(value) | def plmparse(value) | ||
− | + | #THIS ROUTINE REPLACES parsestring() | |
− | + | #this routine will PARSE the incoming stream into valid messages | |
− | + | # value is the complete command | |
− | + | param = {} | |
− | + | #here is a special case, the PLM seems to lock up. | |
− | + | if value == 0x15.chr | |
− | + | log('The PLM stopped responding') | |
− | + | log('Please unplug it, and plug it back in') | |
− | + | log('and do a quick reload router.') | |
− | + | end | |
− | + | while value.length > 2 | |
− | + | case value[1] | |
− | + | when 0x62 # Special case, need to look at flags | |
− | + | if (value[5] & 0x10) == 0x10 # check for extended flag | |
− | + | cmdlen = 23 | |
− | + | else | |
− | + | cmdlen = 9 | |
− | + | end | |
− | + | param['Response'] = 'SndIns' | |
− | + | when 0x50; cmdlen = 11; param['Response'] = 'InsStdMsg' | |
− | + | when 0x51; cmdlen = 25; param['Response'] = 'InsExtMsg' | |
− | + | when 0x68; cmdlen = 4 #Set Insteon ACK Message Byte | |
− | + | when 0x71; cmdlen = 5 #Set Insteon ACK Message Two Bytes | |
− | + | when 0x70; cmdlen = 4 #Set Insteon NACK Message Byte | |
− | + | when 0x63; cmdlen = 5; param['Response'] = 'SndX10' | |
− | + | when 0x52; cmdlen = 4; param['Response'] = 'X10Msg' | |
− | + | when 0x61; cmdlen = 6; param['Response'] = 'SndGrp' | |
− | + | when 0x56; cmdlen = 7; param['Response'] = 'GrpEvntRpt' | |
− | + | when 0x58; cmdlen = 3 #All-Link Cleanup Status Report | |
− | + | when 0x64; cmdlen = 5; param['Response'] = 'StLnk' | |
− | + | when 0x65; cmdlen = 3; param['Response'] = 'CancelLnk' | |
− | + | when 0x53; cmdlen = 10; param['Response'] = 'InsLnkSts' | |
− | + | when 0x69; cmdlen = 3; param['Response'] = 'GetLnk' | |
− | + | when 0x6A; cmdlen = 3; param['Response'] = 'GetNext' | |
− | + | when 0x6C; cmdlen = 3 #Get All-Link Record for Sender | |
− | + | when 0x57; cmdlen = 10; param['Response'] = 'LnkData' | |
− | + | when 0x6F; cmdlen = 12; param['Response'] = 'MngLnk' | |
− | + | when 0x67; cmdlen = 3; param['Response'] = 'RstPLM' | |
− | + | when 0x6B; cmdlen = 4; param['Response'] = 'SetCfg' | |
− | + | when 0x60; cmdlen = 9; param['Response'] = 'GetVersion' | |
− | + | when 0x66; cmdlen = 6 #Set Host Device Category | |
− | + | when 0x72; cmdlen = 3 # RF Sleep | |
− | + | when 0x54; cmdlen = 3; param['Response'] = 'BtnRpt' | |
− | + | when 0x6D; cmdlen = 3; param['Response'] = 'LEDON' | |
− | + | when 0x6E; cmdlen = 3; param['Response'] = 'LEDOFF' | |
− | + | else | |
− | + | log('ERROR IN PLMPARSE- Unknown Command') | |
− | + | debug(value) | |
− | + | ||
− | + | ||
− | + | ||
− | + | return '' | |
− | + | end | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | #Now we know the length the command should be, see if we have it. | |
− | + | #log('waiting for ' + cmdlen.to_s + ' characters...') | |
− | + | #log('length of current input is ' + value.length.to_s) | |
+ | if value.length >= cmdlen | ||
+ | #log('GOT whole response') | ||
+ | #Yes, we have the whole command, Pack it in param | ||
+ | for byt in 1..cmdlen | ||
+ | param['Parameter' + byt.to_s] = padhex("%X" %value[byt - 1]) | ||
+ | end | ||
+ | #now remove it from the string.. | ||
+ | value = value.slice(cmdlen, value.length - cmdlen) | ||
+ | #Send it off for parsing | ||
+ | #log('Sending to EZToDCE:' + param.inspect.to_s) | ||
+ | EZToDCE(param) | ||
+ | else | ||
+ | #log('Still waiting...') | ||
+ | #no, we have NOT received the whole command. | ||
+ | |||
+ | end | ||
+ | end | ||
+ | return value | ||
end | end | ||
def rawX10(value) | def rawX10(value) | ||
− | + | x10MSN = $X10HouseCodes.index[value[0..0]] | |
− | + | x10LSN = $X10UnitCodes.index[value[1..1]] | |
− | + | return x10MSN + x10LSN | |
end | end | ||
def X10Flag(value) | def X10Flag(value) | ||
− | + | return + $X10CommandCodes.index[Value] + '0' | |
end | end | ||
def SndIns | def SndIns | ||
− | + | # create a new PLM command for SndIns | |
− | + | if $wAIT == false | |
− | + | #log('SndIns:currentcmd=' + $currentcmd.to_s) | |
− | + | if $cmdqueue.nitems > 0 | |
− | + | log("SndIns:Queue:" + $aqua + $cmdqueue.nitems.to_s + $grey) | |
− | + | #log('SndIns:' + $cmdqueue.inspect) | |
− | + | param = $cmdqueue[0] | |
− | + | ### have to figure out the command byte 2 here | |
− | + | work = '02'.hex.chr + plmcommand(param) | |
− | + | ### PLM command compilation | |
− | + | for loop in 2..param.keys.nitems | |
− | + | @dummy = param['Parameter' + (loop - 1).to_s].to_s | |
− | + | work+= @dummy.hex.chr | |
− | + | end | |
− | + | conn_.Reconnect() | |
− | + | debugout(work) | |
− | + | conn_.Send(work) | |
− | + | #sleep 0.1 | |
− | + | $wAIT = TRUE | |
− | + | else | |
− | + | log($yellow + 'Queue Empty.' + $grey) | |
− | + | if $rerun == true | |
− | + | log('RERUN=TRUE, RESTARTING') | |
− | + | $rerun = false | |
− | + | mainRestart() | |
− | + | else | |
− | + | log('RERUN Not needed') | |
− | + | if $reported == false | |
+ | log('Reporting Child Devices') | ||
+ | @work = "" | ||
+ | $childdatabases.each_key{ | ||
+ | |insteonID| | ||
+ | log('Child:' + insteonID) | ||
+ | log('Config:' + $childdatabases[insteonID].inspect) | ||
+ | @template = $devicetemplate[insteonID] | ||
+ | @work += insteonID + "\t\t\t" + @template.to_s + "\t\n" | ||
+ | } | ||
+ | log(@work) | ||
+ | cmd = Command.new(device_.devid_, -1001, 1, 2, 54) | ||
+ | cmd.params_[13] = @work | ||
+ | SendCommand(cmd) | ||
− | + | $reported = true | |
− | + | else | |
− | + | log('report not needed') | |
− | + | end | |
− | + | end | |
+ | |||
+ | end | ||
+ | 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 | end | ||
def plmcommand(param) | def plmcommand(param) | ||
− | + | ### this returns the proper Byte2 for the command. | |
− | + | case param['Command'] | |
− | + | when 'GetVersion'; return 0x60.chr | |
− | + | when 'SndIns'; return 0x62.chr | |
− | + | when 'SndGrp'; return 0x61.chr | |
− | + | when 'SndX10'; return 0x63.chr | |
− | + | when 'GetLnk'; return 0x69.chr | |
− | + | when 'GetNext'; return 0x6A.chr | |
− | + | when 'BtnRpt'; return 0x54.chr | |
− | + | when 'GetCfg'; return 0x73.chr | |
− | + | when 'StLnk'; return 0x64.chr | |
− | + | when 'CancelLnk'; return 0x65.chr | |
− | + | when 'MngLnk'; return 0x6F.chr | |
− | + | when 'RstPLM'; return 0x67.chr | |
− | + | when 'SetCfg'; return 0x6B.chr | |
− | + | when 'LEDON'; return 0x6D.chr | |
− | + | when 'LEDOFF'; return 0x6E.chr | |
− | + | ## hack | |
− | + | when 'InsStdMsg' | |
− | + | log('ERROR:PLMCommand encountered a COMMAND of INSSTDMSG') | |
− | + | break | |
− | + | return 0x62.chr | |
− | + | end | |
end | end | ||
def debug(text) | def debug(text) | ||
− | + | work = 'DEBUG:' | |
− | + | for c in 1..text.length | |
− | + | work += padhex("%X" %text[c-1]) + ' ' | |
− | + | end | |
− | + | log($yellow + work + "Length:" + text.length.to_s + $grey) | |
end | end | ||
+ | def debugout(text) | ||
+ | work = 'out:' | ||
+ | for c in 1..text.length | ||
+ | work += padhex("%X" %text[c-1]) + ' ' | ||
+ | end | ||
+ | log($green + work + "Length:" + text.length.to_s + $grey) | ||
+ | end | ||
def debugin(text) | def debugin(text) | ||
− | + | work = 'IN:' | |
− | + | for c in 1..text.length | |
− | + | work += padhex("%X" %text[c-1]) + ' ' | |
− | + | end | |
− | + | log($red + work + "Length:" + text.length.to_s + $grey) | |
end | end | ||
def padhex(hex) | def padhex(hex) | ||
− | + | if hex.length==1 | |
− | + | hex = "0" + hex | |
− | + | end | |
− | + | return hex | |
end | end | ||
def percenttohex(level) | def percenttohex(level) | ||
− | + | # convert from percent to byte | |
− | + | return "%X" %((level.to_i * 2.55)).to_i | |
end | end | ||
def hextopercent(level) | def hextopercent(level) | ||
− | + | return ((level.hex.to_i / 2.55)).to_i | |
+ | end | ||
+ | |||
+ | def hextoTempurature(degree) #Thermostat change hex to tempurature | ||
+ | return ((degree.hex.to_i / 2)).to_i | ||
+ | end | ||
+ | def Tempuraturetohex (degree) #Thermostat Cahnge tempurature to hex | ||
+ | return ((degree.to_1 * 2)).hex | ||
end | end | ||
def log(line) | def log(line) | ||
− | + | $log = File.open("/var/log/pluto/" + device_.devid_.to_s + "_Generic_Serial_Device.log", "a") | |
− | + | $log.puts "(***):" + line.to_s | |
− | + | $log.close | |
end | end | ||
def log2(line) | def log2(line) | ||
− | + | #this will send a message out the the orbiters.. | |
− | + | #/usr/pluto/bin/MessageSend localhost 0 20 1 809 9 "Text to Display" 70 "alert" 182 "30" 251 "??" | |
− | + | cmd = Command.new(device_.devid_, -1000, 1, 1, 809) | |
− | + | cmd.params_[9] = line #text to display | |
− | + | cmd.params_[70] = 'PLMMessage' #Token | |
− | + | cmd.params_[182] = '10' #Timeout in seconds | |
− | + | cmd.params_[251] = '??' | |
− | + | SendCommand(cmd) | |
end | end | ||
def checkChildRecordsinPLM() | def checkChildRecordsinPLM() | ||
− | + | log('Entered CheckChildRecordsinPLM') | |
− | + | # log('In CheckChildRecordsinPLM') | |
− | + | # time to verify all children are in the PLM | |
− | + | # | |
− | + | # log('Total PLM Records:' + $plmdatabase.nitems.to_s) | |
− | + | $plmdatabase.each{|record| | |
− | + | log('Record: = '+ getIIDfromRecord(record) + ' Group:' + getGroupfromRecord(record)) | |
+ | log('checking to see if it needs to be added as a child...') | ||
+ | if existsinchild(getIIDfromRecord(record)) == false | ||
− | + | log(getIIDfromRecord(record) + ' needs to be added to the child database') | |
− | + | addtochild(getIIDfromRecord(record)) | |
− | + | end | |
− | + | } | |
− | + | ||
− | + | $childdatabases.each_key {|child| | |
− | + | if existsinplm(child) == false | |
− | + | log(child + ' needs to be added to PLM') | |
− | + | sendAddtoPLM(child) | |
− | + | else | |
− | + | log(child + ' exists in PLM') | |
− | + | end | |
− | + | ||
− | + | #now to scan the childs database | |
− | + | for record in 1..($childdatabases[child].nitems - 1) | |
− | + | @test = $childdatabases[child][record] | |
− | + | if existsinplm(getIIDfromRecord(@test)) == false | |
− | + | log(getIIDfromRecord(@test) + ' needs to be added to PLM') | |
− | + | sendAddtoPLM(getIIDfromRecord(@test)) | |
− | + | else | |
− | + | log(getIIDfromRecord(@test) + ' exists in PLM') | |
− | + | end | |
− | + | #Also check to see if it needs to be added in the childdatabases | |
− | + | end | |
+ | } | ||
end | end | ||
def existsinplm(insteonid) | def existsinplm(insteonid) | ||
− | + | result = false | |
− | + | $plmdatabase.each{|record| | |
− | + | #log(insteonid + '==' + getIIDfromRecord(record)) | |
− | + | if insteonid == getIIDfromRecord(record) | |
− | + | result = true | |
− | + | end | |
− | + | } | |
− | + | return result | |
− | + | ||
end | end | ||
def existsinchild(insteonid) | def existsinchild(insteonid) | ||
− | + | log('ExistsinChild:InsteonID:' + insteonid) | |
− | + | result = false | |
− | + | $childdatabases.each_key{|record| | |
− | + | if insteonid == record | |
− | + | result = true | |
− | + | end | |
− | + | } | |
+ | log('ExistsinChild result:FALSE') if result == false | ||
+ | log('ExistsinChild result:TRUE') if result == true | ||
+ | return result | ||
end | end | ||
def addtochild(insteonID) | def addtochild(insteonID) | ||
− | + | log('addtochild Routne called') | |
− | + | log('Adding ' + insteonID + ' to the child database...') | |
− | + | if insteonID.length == 2 then | |
− | + | log('Child is X10') | |
− | + | $state[insteonID] = 0 | |
+ | else | ||
+ | log('Child is Insteon') | ||
+ | $childdatabases[insteonID] = ['****************'] | ||
+ | sendPing(insteonID) | ||
+ | $rerun = true | ||
+ | end | ||
+ | end | ||
+ | |||
+ | |||
+ | def removefromchild(insteonID) | ||
+ | log('Removing ' + insteonID + ' from child database') | ||
+ | $childdatabases.delete(insteonID) | ||
+ | $state.delete(insteonID) | ||
+ | end | ||
+ | def removefromplm(insteonID) | ||
+ | log('Removing from plm') | ||
+ | $plmdatabase.each{|record| | ||
+ | #log(insteonid + '==' + getIIDfromRecord(record)) | ||
+ | if insteonID == getIIDfromRecord(record) | ||
+ | debug(record) | ||
+ | log('Found Record, Deleting') | ||
+ | $plmdatabase.delete(record) | ||
+ | |||
+ | #now, we have to remove it from the device. | ||
+ | param = {'Command' =>'MngLnk', | ||
+ | 'Parameter1' => '80', #DELETE | ||
+ | 'Parameter2' => record[0..1], #control byte | ||
+ | 'Parameter3' => record[2..3], #group | ||
+ | 'Parameter4' => record[4..5],#HB | ||
+ | 'Parameter5' => record[6..7],#MB | ||
+ | 'Parameter6' => record[8..9],#LB | ||
+ | 'Parameter7' => record[10..11],#data1 | ||
+ | 'Parameter8' => record[12..13],#data2 | ||
+ | 'Parameter9' => record[14..15] #data3 | ||
+ | |||
+ | } | ||
+ | log(param.inspect) | ||
+ | $cmdqueue << param | ||
+ | end | ||
+ | } | ||
end | end | ||
def sendAddtoPLM(insteonID) | def sendAddtoPLM(insteonID) | ||
− | + | log('Adding ' + insteonID + ' to the PLM database...') | |
− | + | #This adds a record into the PLM | |
− | + | @insID = insteonID.split('.') | |
− | + | param = {'Command' => 'MngLnk', | |
− | + | 'Parameter1' => '40', #control code -- add new record as Controller | |
− | + | 'Parameter2' => 'C2', #All Link Record Flags AKA Record Control Byte | |
− | + | 'Parameter3' => '01', #All Link Group | |
− | + | 'Parameter4' => @insID[0], #HB | |
− | + | 'Parameter5' => @insID[1], #MB | |
− | + | 'Parameter6' => @insID[2], #LB | |
− | + | 'Parameter7' => '01', #Link Data 1 ON-Level | |
− | + | 'Parameter8' => '01', #Link Data 2 Ramp Rate | |
− | + | 'Parameter9' => 'FF'} #Link Data 3 not used | |
− | + | if $wAIT == true | |
− | + | $cmdqueue.insert(1, param) | |
− | + | else | |
− | + | $cmdqueue.insert(0, param) | |
− | + | end | |
− | + | SndIns() | |
end | end | ||
def getIIDfromRecord(recordstring) | def getIIDfromRecord(recordstring) | ||
− | + | #this extracts the insteonID string from the record. | |
− | + | #log('getIIDfromRecord::recordstring:' + recordstring) | |
− | + | @idhb = recordstring[4..5] | |
− | + | @idmb = recordstring[6..7] | |
− | + | @idlb = recordstring[8..9] | |
− | + | @result = @idhb + '.' + @idmb + '.' +@idlb | |
− | + | #log('GetIIDfromRecord: Found ID:' + @result) | |
− | + | return @result | |
end | end | ||
def processBroadcastMessage(param) | def processBroadcastMessage(param) | ||
− | + | #search the child databases for responders, | |
− | + | #and fire COMMANDS for each responder. 06Feb08 | |
− | + | #and fire events for each responder.XXXXXXXXXXXXX | |
− | + | #Message flag is in parameter9 Group command 0xCx (All-Link Broadcast Message Pg 42.) | |
− | + | #Group is in parameter8 | |
− | + | #From InsteonID is parameters 3, 4, 5 | |
− | + | group = param['Parameter8'] | |
− | + | from = padhex(param['Parameter3']) + '.' | |
− | + | from += padhex(param['Parameter4']) + '.' | |
− | + | from += padhex(param['Parameter5']) | |
− | + | log('Looking for ' + from + ' Group:' + group) | |
− | + | log('Showing Parameter10:' + param['Parameter10'].to_s) | |
− | + | #Ok, now have to search child databases for from AND group AND responder | |
− | + | $childdatabases.each_key{|child| | |
− | + | #log('Searching:' + child) | |
− | + | for rec in 1..($childdatabases[child].nitems - 1) | |
− | + | record = $childdatabases[child][rec] | |
− | + | if getIIDfromRecord(record) == from # First, look for Insteon ID | |
− | + | #log('Found ID') | |
− | + | if getGroupfromRecord(record) == group #next, Group | |
− | + | #log('Found Group') | |
− | + | if isResponderRecord(record) # is a responder? | |
− | + | #log('Found Responder') | |
− | + | #figure out the child devicenum | |
− | + | from = $children[child] | |
− | + | #figure out the command | |
− | + | case param['Parameter10'].hex | |
− | + | when 0x11 #on | |
− | + | reportStatus(from, 100) | |
− | + | when 0x13 #off | |
− | + | reportStatus(from, 0) | |
− | + | when 0x6B # Thermostat Command On/OFF/AUTO | |
− | + | case param['Parameter11'].to_s | |
− | + | when '09' #status to OFF | |
− | + | #need to set current temp | |
− | + | reportStatus(from, 0) | |
− | + | else | |
− | + | #check thermostat for state and update and set current temp | |
− | + | #reportStatus(from, 100) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
end | end | ||
− | + | when 0x6C # Thermostat Command Cool Point | |
− | + | tempurature =param['Parameter11'] /2 #temp in hex need to devide by 2 = current cool point | |
+ | #reportStatus(from,tempurature) | ||
+ | when 0x6D# Thermostat Command Heat Point | ||
+ | tempurature =param['Parameter11'] /2 #temp in hex need to devide by 2 = current heat point | ||
+ | #reportStatus(from,tempurature) | ||
+ | when 0x17 #dim/brighten -ignore | ||
+ | level = 0 | ||
+ | when 0x18 # STOP dim/brighten - sendgetstatus | ||
+ | level = 0 | ||
+ | sendGetChildStatus(child) | ||
+ | else | ||
+ | level = 0 | ||
+ | log('Command is other than ON/OFF/Dim/Brighten') | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | } | ||
+ | end | ||
− | + | def reportStatus(from, level) | |
− | + | log('From:' + from.to_s) #shows child id | |
− | + | log('current State:' + $state[from].to_s) | |
− | + | log('Wanted State:' + level.to_s) | |
− | + | case $state[from] | |
− | + | when 0 | |
− | + | if level >=1 | |
− | + | cmd = Command.new(from, from, 1, 1, 192) #on | |
− | + | cmd.params_[120] = "1" | |
− | + | SendCommand(cmd) | |
− | + | cmd = Command.new(from, from, 1, 1, 184) | |
− | + | cmd.params_[76] = level.to_s | |
− | + | cmd.params_[120] = "1" | |
− | + | SendCommand(cmd) | |
− | + | end | |
− | + | when 100 | |
− | + | if level >= 1 | |
− | + | cmd = Command.new(from, from, 1, 1, 184) | |
− | + | cmd.params_[76] = level.to_s | |
− | + | cmd.params_[120] = "1" | |
− | + | SendCommand(cmd) | |
− | + | else | |
− | + | cmd = Command.new(from, from, 1, 1, 193) # off | |
− | + | cmd.params_[120] = "1" | |
− | + | SendCommand(cmd) | |
− | + | end | |
− | + | else | |
− | + | if level == 100 | |
− | + | cmd = Command.new(from, from, 1, 1, 193) #off | |
− | + | cmd.params_[120] = "1" | |
− | + | SendCommand(cmd) | |
− | + | cmd = Command.new(from, from, 1, 1, 192) # on | |
+ | cmd.params_[120] = "1" | ||
+ | SendCommand(cmd) | ||
+ | end | ||
+ | cmd = Command.new(from, from, 1, 1, 184) #SetLevel | ||
+ | cmd.params_[76] = level.to_s | ||
+ | cmd.params_[120] = "1" | ||
+ | SendCommand(cmd) | ||
+ | end | ||
+ | log('ReportStatus: device:' + from.to_s + ' Status:' + level.to_s) | ||
+ | $state[from] = level | ||
end | end | ||
def isResponderRecord(recordstring) | def isResponderRecord(recordstring) | ||
− | + | work = recordstring[0..1].hex | |
− | + | if (work & 0x40) == 0x40 #check bit 6 | |
− | + | result = false #signifies Controller record | |
− | + | else | |
− | + | result = true #signifies Responder record | |
− | + | end | |
− | + | return result | |
end | end | ||
def getGroupfromRecord(recordstring) | def getGroupfromRecord(recordstring) | ||
− | + | #this extracts the GROUP from the record. | |
− | + | if recordstring == nil | |
− | + | return '00' | |
− | + | else | |
− | + | return recordstring[2..3] | |
− | + | end | |
end | end | ||
def getdeltafromconfig(insteonID) | def getdeltafromconfig(insteonID) | ||
− | + | #This returns the delta from the child. | |
− | + | @work = $childdatabases[insteonID][0] # the settings stored in [0] | |
− | + | if @work == nil | |
− | + | return '00' | |
− | + | else | |
− | + | return @work[6..7] | |
− | + | end | |
end | end | ||
def sendGetChildStatus(insteonID) | def sendGetChildStatus(insteonID) | ||
− | + | #log('sendGetChildStatus Called') | |
− | + | if insteonID.length != 2 #X10 device | |
− | + | @insID = insteonID.split('.') | |
− | + | param = {'Command' => 'SndIns', | |
− | + | 'Parameter1' => @insID[0], | |
− | + | 'Parameter2' => @insID[1], | |
− | + | 'Parameter3' => @insID[2], | |
− | + | 'Parameter4' => '0F', #flags | |
− | + | 'Parameter5' => '19', #Status Request | |
− | + | 'Parameter6' => '00'} #not used. | |
− | + | $cmdqueue << param | |
− | + | SndIns() | |
− | + | #Returned response will have cmd1 = DBDelta | |
+ | #Returned response will have cmd2 = ON-Level | ||
+ | else | ||
+ | log('X10 does not report status') | ||
+ | end | ||
+ | end | ||
+ | def islast(record) | ||
+ | #high water mark | ||
+ | return false if (record[0..1].hex & 0x02) == 0x02 | ||
+ | return true | ||
end | end | ||
+ | def isinuse(record) | ||
+ | return true if (record[0..1].hex & 0x80) == 0x80 | ||
+ | return false | ||
+ | end | ||
+ | |||
+ | def iscontroller(record) | ||
+ | return true if (record[0..1].hex & 0x40) == 0x40 | ||
+ | return false | ||
+ | end | ||
+ | def group(record) | ||
+ | return record[2..3] | ||
+ | end | ||
+ | def remoteid(record) | ||
+ | |||
+ | @insteonID = record[4..5] + '.' | ||
+ | @insteonID += record[6..7] + '.' | ||
+ | @insteonID += record[8..9] | ||
+ | return @insteonID | ||
+ | end | ||
+ | |||
+ | def findresponderrecord(masterid, slaveid, groupid) | ||
+ | # log(masterid + ':' + slaveid + ':' + groupid) | ||
+ | $childdatabases[slaveid].each{|check| | ||
+ | # log('Record:' + check.to_s) | ||
+ | if iscontroller(check.to_s) == false #responder record | ||
+ | # log('found responder record') | ||
+ | # log('remoteid:' + remoteid(check.to_s)) | ||
+ | if remoteid(check.to_s) == masterid # found | ||
+ | # log('Found Controller ID in responder record') | ||
+ | if group(check.to_s) == groupid | ||
+ | # log('Group Matches') | ||
+ | #found group | ||
+ | return true | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | } | ||
+ | return false | ||
+ | end | ||
+ | def findcontrollerrecord(masterid, slaveid, groupid) | ||
+ | # log(masterid + ':' + slaveid + ':' + groupid) | ||
+ | $childdatabases[masterid].each{|check| | ||
+ | # log('Record:' + check.to_s) | ||
+ | if iscontroller(check.to_s) == true #controller | ||
+ | # log('found controller record') | ||
+ | if remoteid(check.to_s) == slaveid # found | ||
+ | # log('found Responder ID in Controller record') | ||
+ | if group(check.to_s) == groupid | ||
+ | # log('Group Matches') | ||
+ | #found group | ||
+ | return true | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | } | ||
+ | return false | ||
+ | end | ||
# time to define a structure to save the raw data in hex | # time to define a structure to save the raw data in hex | ||
# starts at [0] | # starts at [0] | ||
− | # Bytes Meaning | + | # Bytes Meaning |
− | # 0-1 Device Category | + | # 0-1 Device Category |
− | # 2-3 Device SubCategory | + | # 2-3 Device SubCategory |
− | # 4-5 Device Firmware | + | # 4-5 Device Firmware |
− | # 6-7 Database Delta | + | # 6-7 Database Delta |
− | # 8-9 reserved | + | # 8-9 reserved |
− | # 10-11 reserved | + | # 10-11 reserved |
− | # 12-13 reserved | + | # 12-13 reserved |
− | # 14-15 reserved | + | # 14-15 reserved |
###### First database record below (in same format its read from the device) | ###### First database record below (in same format its read from the device) | ||
###### This is the same format as an ALL-Link Record Response from the PLM | ###### This is the same format as an ALL-Link Record Response from the PLM | ||
###### (0x57) bytes 3..10 | ###### (0x57) bytes 3..10 | ||
− | # 16-17 record control byte | + | # 16-17 record control byte |
− | # 18-19 Group | + | # 18-19 Group |
− | # 20-21 ID HB | + | # 20-21 ID HB |
− | # 22-23 ID MB | + | # 22-23 ID MB |
− | # 24-25 ID LB | + | # 24-25 ID LB |
− | # 26-27 Link Specific Data1 | + | # 26-27 Link Specific Data1 |
− | # 28-29 Link Specific Data2 | + | # 28-29 Link Specific Data2 |
− | # 30-31 Link Specific Data3 | + | # 30-31 Link Specific Data3 |
###### | ###### | ||
− | # 32-47 | + | # 32-47 next database record... |
+ | |||
</pre> | </pre> |
Latest revision as of 10:30, 3 July 2016
Version | Status | Date Updated | Updated By |
---|---|---|---|
710 | Unknown | N/A | N/A |
810 | Unknown | N/A | N/A |
1004 | Unknown | N/A | N/A |
1204 | Unknown | N/A | N/A |
1404 | Unknown | N/A | N/A |
Usage Information |
#### Written by Dan Damron #### #373 Private Method Listing #### def mainStart() ## This is called FIRST, reruns cannot call this. #Register Message Interceptor @interceptor = Command.new(device_.devid_, -1000, 1, 5, 37) @interceptor.params_[2] = device_.devid_.to_s SendCommand(@interceptor) #Get the PLM Database sendGetLink #get Child devices log('Finding Children..') device_.childdevices_.each{|c| if device_.childdevices_[c.to_s.to_i].devdata_[12].include? "Group" log('FOUND A GROUP') else $children[device_.childdevices_[c.to_s.to_i].devdata_[12].chomp.lstrip.rstrip] = c.to_s.to_i end} $children.keys.each{|c| log(c + ' = ' + $children[c].to_s) } log('reading stored Child configuration:') $children.keys.each{|c| #Get each Childs configuration $state[$children[c]] = 0 getdeviceconfig(c) # #the above getdeviceconfig packs $configparams array log('Configuration for ' + c + ' = ' + $configparams.inspect.to_s) } log('********************************************************') #get childs actual configuation and status $children.keys.each{|c| sendGetChildStatus(c)} SndIns() end def mainRestart() #We have hashes already set up. $childdatabases.each_key{|@insteonID| $state[$children[@insteonID]] = 0 sendGetChildStatus(@insteonID)} SndIns() end def setdeviceconfig(insteonid, configurestring) @deviceid = $children[insteonid] @cmdfrom = device_.devid_ @cmdto = 4 #general info plugin @priority = 1 @type=1 #command @cmdid = 246 #set up command.. @cmd = Command.new(@cmdfrom, @cmdto, @priority, @type, @cmdid) @cmd.params_[2] = @deviceid.to_s @cmd.params_[52] = '59' # Configuration @cmd.params_[5] = configurestring SendCommand(@cmd) log('SetDeviceConfig:' + @cmd.to_s) #log('SetDeviceConfig:' + configurestring) #log('Configuration Saved - will be available on next reload') end def getdeviceconfig(insteonid) @deviceid = $children[insteonid] @configstring = '' begin @configstring = device_.childdevices_[@deviceid].devdata_[59].to_s rescue log('Device ID = ' + @deviceid.to_s) log($red + 'Error - Child has no configuration'+ $grey) log('Setting initial value of "****************"') setdeviceconfig(insteonid, ('*' * 16)) @configstring = '*' * 16 sendPing(insteonid) end if @configstring == '' $configparams = ['****************'] log('CAUGHT BLANK RECORD') setdeviceconfig(insteonid, ('*' * 16)) sendPing(insteonid) else $configparams = @configstring.unpack('a16' * (@configstring.length / 16)) $devicetemplate[insteonid] = getdevicetemplate($configparams[0][0..1], $configparams[0][2..3]) end #log($yellow + 'getdeviceconfig:' + $configparams.inspect + $grey) #add the configuration parameters to the child database $childdatabases[insteonid] = $configparams #get the device type end def sendGetLink() #lets just see exactly what is in the PLM database param = {'Command' => 'GetLnk'} $cmdqueue << param SndIns() end def sendGetNext() param = {'Command' => 'GetNext'} if $wAIT == true $cmdqueue.insert(1, param) else $cmdqueue.insert(0,param) end SndIns() end def sendRemoteGetLink(insteonID) # Read First ALDB Record # a few variables need to be set up here.. $recordof = insteonID # save the insteon ID insID = insteonID.chomp.split('.') # get the seperate bytes $remoteDBOffsetMSB = 0x0F # initial offset $remoteDBOffsetLSB = 0xF8 # initial LSB offset param = {'Command' => 'SndIns', 'Parameter1' => insID[0], #HB 'Parameter2' => insID[1], #MB 'Parameter3' => insID[2], #LB 'Parameter4' => '0F', #Flags 'Parameter5' => '28', #Cmd1 'Parameter6' => "%X" %$remoteDBOffsetMSB #Cmd2 Set MSB Offset } $cmdqueue << param # repeat last param for each byte to read (F8..FF)=first record for x in 0..7 param = {'Command' => 'SndIns', 'Parameter1' => insID[0], #HB 'Parameter2' => insID[1], #MB 'Parameter3' => insID[2], #LB 'Parameter4' => '0F', #Flags 'Parameter5' => '2B', #Cmd1 Peek 'Parameter6' => "%X" %($remoteDBOffsetLSB + x) #Cmd2 } $cmdqueue << param end end def sendRemoteGetNext(insteonID) insID = insteonID.chomp.split('.') # get the seperate bytes ### Do NOT forget to check to see if we need to decrease the MSB if $remoteDBOffsetLSB == 0x00 #OffsetMSB needs to be decreased, and LSB needs reset. $remoteDBOffsetMSB = $remoteDBOffsetMSB - 1 $remoteDBOffsetLSN = 0xFF # the next line will decrease this by 8 end # decrease DBOffsetLSB by 0x08 $remoteDBOffsetLSB = $remoteDBOffsetLSB - 0x08 for x in 0..7 param = {'Command' => 'SndIns', 'Parameter1' => insID[0], #HB 'Parameter2' => insID[1], #MB 'Parameter3' => insID[2], #LB 'Parameter4' => '0F', #Flags 'Parameter5' => '2B', #Cmd1 Peek 'Parameter6' => "%X" %($remoteDBOffsetLSB + x) #Cmd2 } #log('sendRemoteGetNet:added to queue:' + param.inspect) if $wAIT == true $cmdqueue.insert(x + 1, param) else $cmdqueue.insert(x,param) end end end ### Main command parsing routine is EZToDCE def EZToDCE(param) #param contains a hash of EZBridge command structure #log($blue + 'Queue:' + $cmdqueue[0].inspect + $grey) #log($blue + 'Param:' + param.inspect + $grey) #log($blue + 'currentcmd:' + $currentcmd.to_s + $grey) #checkWait(param) case param['Response'] # Standard RESPONSES (to commands) 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 SndIns() 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 ### BUG FOUND ### When the EZBridge receives a command from an EXTERNAL source ### ie not from this device, cmdqueue will be nil, and the code below ### fails. Have to check against that. if $cmdqueue.length > 0 #First, check the response to make sure the command made it ok. if param['Parameter9'].to_i == 6 #Ack received #log('Sending to ProcessACK') processACK(param) else # NACK received - command failed. log('Command NACKED') end else #Response received for another device. log('Response detected for a command that was not sent by me') end when 'SndX10' log('Response detected for SndX10') if param['Parameter5'].to_i == 6 #ack log('X10 Command Successfull') cmdComplete SndIns() else log('X10 Command FAILED') cmdComplete SndIns() end when 'StLnk' when 'CancelLnk' when 'SetDev' when 'RstPLM' #Reset Response $timeout = 1 cmdComplete SndIns() when 'GetLnk' if param['Parameter3'].to_i == 6 #ack log('GetLnk ACKED') #if we get this, we should get a AllLink Record Response next else log('GetLnk NACKED') # The PLM is BLANK #have to add records to the PLM here. cmdComplete ### FINISHED WITH GetLnk checkChildRecordsinPLM() SndIns() end when 'GetNext' if param['Parameter3'].to_i == 6 #ack log('sendGetNext ACKED') #if we get this, we should get a AllLink Record Response next else log('sendGetNext NACKED') #we get this when there are no more records cmdComplete #FINISHED with GetNext # if we are here, we are in config mode # so, next is to check to make sure the # childrens insteon ID is in the PLM checkChildRecordsinPLM() # now, to make sure that all the records in the PLM are sensed as children SndIns() end when 'SetCfg' # response from Setcfg command if param['Parameter4'].to_i == 6 #ack log('SetCfg Completed') cmdComplete SndIns() else log('SetCfg NACKED') end when 'GetLnkData' when 'LEDON' when 'LEDOFF' when 'MngLnk' if param['Parameter12'].to_i == 6 log('MngLnk => ACK') else log('MngLnk => NACK') end cmdComplete SndIns() 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 0x0 #log('REROUTING to processExternalCommand(param)') processExternalCommand(param) when 0x1 #Assign to Group ### This is a broadcast message sent # from a PING command # or from a StartLink... log('Caught Assign to Group Message from Device') ### BUG HERE #have to check flags to see if this is a broadcast message log('Checking if this is a broadcast message') log('Flags:' + param['Parameter9']) if (param['Parameter9'].hex & 0x80) == 0x80 log('Message IS BROADCAST') #recvComplete processDeviceInfo(param) # check to see if current cmd is for this broadcast.. log('Current Command:' + $cmdqueue[0]['Parameter5']) if $cmdqueue[0]['Parameter5'] == '10' #log('Clearing PING Command') $currentcmd = 0 cmdComplete SndIns() else log('CURRENT CMD IS NOT PING - NOT CLEARING') end else log('Message is NOT Broadcast') end when 0x2 #Delete from Group when 0x10 # PING #this is where I catch the InsStdMsg for ping. log('Caught PING Message from Device') $currentcmd = 1 when 0x11 # ON log('Caught Insteon ON from INTERNAL source') insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] log('Current DIM level:' + param['Parameter11']) reportStatus(myDevFrom, hextopercent(param['Parameter11'])) $currentcmd = 0 cmdComplete SndIns() when 0x13 # OFF insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] reportStatus(myDevFrom, 0) $currentcmd = 0 cmdComplete #log('EVENT and state SENT!!!.48:[10]=0') SndIns() #####Thermostat Does Not report Status correctly Yet. Have to figure out reportStatus### when 0x6A #Thermostat Control Get Zone Data (Temp, Setpoint,Humidity) log('Thermostat returned Zone Info: ' + param['Parameter11'].to_s) insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #reportStatus(myDevFrom, hextopercent(param['Parameter11'])) $currentcmd = 0 cmdComplete SndIns() when 0x6B #Thermostat Control Command Handle Response log('Thermostat returned: ' + param['Parameter11'].to_s) case param['Parameter11'].to_s when '06' # ON/Auto # $ThermostatStatus = 'ON/Auto' ##not used insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #log('Current Thermostat State:' + $ThermostatStatus) #reportStatus(myDevFrom, 6) $currentcmd = 0 cmdComplete SndIns() when '09' #OFF # $ThermostatStatus = 'OFF' ## not used may be for reportstatus insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #log('Current Thermostat State:' + $ThermostatStatus) #reportStatus(myDevFrom, 9) $currentcmd = 0 cmdComplete SndIns() when '04' # Heat #$ThermostatStatus = 'HEAT' insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #log('Current Thermostat State:' + $ThermostatStatus) #reportStatus(myDevFrom, 4) $currentcmd = 0 cmdComplete SndIns() when '05' # Cool #$ThermostatStatus = 'COOL' insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #log('Current Thermostat State:' + $ThermostatStatus) #reportStatus(myDevFrom, 5) $currentcmd = 0 cmdComplete SndIns() when '07' # Fan On 2#$ThermostatStatus = 'COOL' insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #log('Current Thermostat State:' + $ThermostatStatus) #reportStatus(myDevFrom, 5) $currentcmd = 0 cmdComplete SndIns() when '08' # Fan Off #$ThermostatStatus = 'COOL' insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] #log('Current Thermostat State:' + $ThermostatStatus) #reportStatus(myDevFrom, 5) $currentcmd = 0 cmdComplete SndIns() end when 0x6C #Thermostat Control Get Zone Cool Point Data log('Thermostat returned Zone Info: ' + param['Parameter11'].to_s) insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] log('Current Zone level:' + param['Parameter11'].to_s) #reportStatus(myDevFrom, hextopercent(param['Parameter11'])) $currentcmd = 0 cmdComplete SndIns() when 0x6D #Thermostat Control Get Zone Heat Point Data log('Thermostat returned Zone Info: ' + param['Parameter11'].to_s) insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] log('Current Zone level:' + param['Parameter11'].to_s) #reportStatus(myDevFrom, hextopercent(param['Parameter11'])) $currentcmd = 0 cmdComplete SndIns() when 0x19 # Status Report # now to clear the currentcmd and remove command from the queue $currentcmd = 0 cmdComplete log('Processing 0x19 Status Report') #This is where I get the database delta (in cmd1) insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb #First, to compare the DB Delta with current config. #Database Delta... delta = param['Parameter10'].to_s log($blue + 'Database Delta=' + delta + $grey) log($blue + 'Configuration is:' + getdeltafromconfig(insID) + $grey) if delta == getdeltafromconfig(insID) if $children[insID] != nil myDevFrom = $children[insID] myDevTo = -1000 #DCE Router myPriority = 1 myType = 2 #Event #Send an EVENT to report STATE ONLY if database has not changed # AND child exists in pluto reportStatus(myDevFrom, hextopercent(param['Parameter11'])) end else log('Databse CHANGED -getting remote database') #here, I have to WIPE the databse # to prepare it for new data ### here is where the DAMN CONFIG was reset!!! oldconfigstring = $childdatabases[insID][0] $childdatabases[insID] = [oldconfigstring] log('Setting Database Config') $childdatabases[insID][0][6..7] = delta savechilddatabases(insID) sendRemoteGetLink(insID) end # finally, to check execute next command... SndIns() when 0x28 # Set Address MSB log('Received SET Address MSB from remote device') $currentcmd = 0 $remoteLinkRecord = '' cmdComplete SndIns() when 0x2B # peek ### BUG HERE... have to verify response is a PEEK command #response command is stored in parameter10 if param['Parameter10'].hex == 0x2B # this is the peek command cmdComplete log('Received PEEK from remote Device! DATA=' + param['Parameter11']) checkPeekData(param) $currentcmd = 0 SndIns() else log('Waiting for remote PEEK response, but got :' + param['Parameter10']) end else end when 'X10Msg' log($purple + 'X10 Message Received' + $grey) if param['Parameter4'].hex == 0x00 log('This byte is a House/Unit Code') hn = param['Parameter3'][0].chr ln = param['Parameter3'][1].chr $x10byte1 = $X10HouseCodes[hn] $x10byte1 += $X10UnitCodes[ln] log('Translated X10 House/Unit Code:' + $x10byte1) else log('This byte is a House/Command Code') hn = param['Parameter3'][0].chr ln = param['Parameter3'][1].chr $x10byte2 = $X10HouseCodes[hn] $x10byte2 += $X10CommandCodes[ln] log('Translated X10 Command Code:' + $x10byte2) log('X10 Command ready to send:' + $x10byte1 + ' ' + $x10byte2) case $X10CommandCodes[ln] when 'On' #Send ON to lmnce if $children[$x10byte1] == nil log('I do not control this X10 device') else cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 192) cmd.params_[120] = "1" SendCommand(cmd) end when 'Off' #Send OFF to lmnce if $children[$x10byte1] == nil log('I do not control this X10 device') else cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 193) cmd.params_[120] = "1" SendCommand(cmd) end when 'Bright' if $children[$x10byte1] == nil log('I do not control this X10 device') else #send a command to set the state + 1 @curstate = ($state[$x10byte1] / 100) * 32 #get equal 32 steps $state[$x10byte1] = ((@curstate + 1) / 32) * 100 cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 184) cmd.params_[76] = $state[$x10byte1].to_s cmd.params_[120] = "1" SendCommand(cmd) #$state[$x10byte1] = ($state[$x10byte1] / 100) * 32 end when 'Dim' @curstate = ($state[$x10byte1] / 100) * 32 #get equal 32 steps $state[$x10byte1] = ((@curstate - 1) / 32) * 100 cmd = Command.new($children[$x10byte1].to_i, -1000, 1, 1, 184) cmd.params_[76] = $state[$x10byte1].to_s cmd.params_[120] = "1" SendCommand(cmd) when 'All Lights Off' log('ALL Lights OFF Command not implemented') when 'All Lights On' log('All Lights ON Command not implemented') when 'Status Request' log('Status Request Command not implemented') when 'Hail Ack' log('Hail Ack Command not implemented') end end when 'InsLnkSts' log('InsLnkSts Received') when 'BtnRpt' log('Button Report Received') when 'UsrRst' log('User Reset Response Received') when 'GrpEvntRpt' log('Group Event Report Received') when 'LnkData' processLnkData(param) # Other messages when 'PLMTimeout' log('PLM Timeout detected.. resetting EZBridge') resetcmd = {'Command' => 'Reset'} if $wAIT == true $cmdqueue.insert(1, resetcmd) else $cmdqueue.insert(0,resetcmd) end 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'} if $wAIT == true $cmdqueue.insert(1, resetcmd) else $cmdqueue.insert(0,resetcmd) end sleep 15 $wAIT = false SndIns() when 'LongAck' log('-----XXXXXXX' + param['Response']) # Error - seems to show up after PLMEchoError resetcmd = {'Command' => 'Reset'} if $wAIT == true $cmdqueue.insert(1, resetcmd) else $cmdqueue.insert(0,resetcmd) end sleep 15 $wAIT = false SndIns() else log('-----XXXXXXX UNKNOWN Response Received') end end ### Support routine for EZToDCE def processLnkData(param) #Caught a LnkData Response log('LnkData Message Received') log(param.inspect) if param['Parameter6'] == '00' and param['Parameter7'] == '00' log('FOUND X10 DEVICE!!!') insteonID = padhex(param['Parameter5']) else insteonID = padhex(param['Parameter5']) + '.' + padhex(param['Parameter6']) + '.' + padhex(param['Parameter7']) end group = param['Parameter4'] recflags = param['Parameter3'] lnkdata1 = param['Parameter8'] lnkdata2 = param['Parameter9'] lnkdata3 = param['Parameter10'] #pack string to store for PLM Database @currentrecord = recflags + group @currentrecord += param['Parameter5'] + param['Parameter6'] + param['Parameter7'] @currentrecord += lnkdata1 + lnkdata2 + lnkdata3 #Add to plmdatabase $plmdatabase << @currentrecord log('record Flags:' + recflags) #log('PLM database=' +$plmdatabase.inspect) if (recflags[0] & 0x80) == 0x80 # Record is in use if true end if (recflags[0] & 0x40) == 0x40 # Controller if true log('Controller') else log('Responder') end log('Insteon ID:' + insteonID + ', Group:' + group) cmdComplete sendGetNext() end ### Support Routine for EZToDCE def processExternalCommand(param) #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 ### have to check here if child is mine! # This is where I have to check for a broadcast command.. #if so, search the child databases for responders, #and fire events for each responder. #Message flag is in parameter9 Group command 0xCx (All-Link Broadcast Message Pg 42.) #Group is in parameter8 #From InsteonID is parameters 3, 4, 5 if (param['Parameter9'].hex & 0xC0) == 0xC0 # Message is Broadcast log('Rerouting to processBroadcastMessage') processBroadcastMessage(param) else log('Process External Command:') log('Param:' + param.inspect) # there is no ack here. Simply Send COMMANDS back to DCE # and Complete the recv.. case param['Parameter10'].hex #this is the command when 0x01 #Assign to Group log('Caught EXTERNAL Assign to Group') processDeviceInfo(param) recvComplete when 0x02 #Delete from Group when 0x02 #Delete from Group log('Caught EXTERNAL Delete from Group') recvComplete when 0x10 # PING log('Caught EXTERNAL Insteon PING result') recvComplete when 0x11 #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 log('From:' +insID) log('Device:' + $children[insID].to_s) myDevFrom = $children[insID] # check to see if I own child if myDevFrom == nil log('I do not control this device.') else reportStatus(myDevFrom, hextopercent(param['Parameter11'])) $currentcmd = 0 end recvComplete when 0x13 #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] if myDevFrom == nil log('I do not control this device.') else reportStatus(myDevFrom, 0) $currentcmd = 0 #log('EVENT and state SENT!!!.48:[10]=0') end recvComplete when 0x6A #Thermostat Zone Command log('Caught EXTERNAL Insteon Thermostat result') #on level is in cmd2 insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] if myDevFrom == nil log('I do not control this device.') else #case param['Parameter11'].to_s #when '00' reportStatus(myDevFrom, hextoTempurature(param['Parameter11'])) $currentcmd = 0 #when '60' #humidity #when '20'#setpoint #log('EVENT and state SENT!!!.48:[10]=0') end when 0x6B #Thermostat Mode Command log('Caught EXTERNAL Insteon Thermostat result') #on level is in cmd2 ie( HEAT(0x04), COOL(0x05), or AUTO(0x06)) insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] if myDevFrom == nil log('I do not control this device.') else #reportStatus(myDevFrom, 0) $currentcmd = 0 #log('EVENT and state SENT!!!.48:[10]=0') end when 0x6C #Thermostat Zone Cool Command log('Caught EXTERNAL Insteon Thermostat result') #on level is in cmd2 insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] if myDevFrom == nil log('I do not control this device.') else reportStatus(myDevFrom, hextoTempurature(param['Parameter11'])) $currentcmd = 0 #log('EVENT and state SENT!!!.48:[10]=0') end when 0x6D #Thermostat Zone Heat Command log('Caught EXTERNAL Insteon Thermostat result') #on level is in cmd2 insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = insHb + "." + insMb + "." + insLb myDevFrom = $children[insID] if myDevFrom == nil log('I do not control this device.') else reportStatus(myDevFrom, hextoTempurature(param['Parameter11'])) $currentcmd = 0 #log('EVENT and state SENT!!!.48:[10]=0') end when 0x15; log('Caught EXTERNAL Insteon Brighten Result') when 0x16; log('Caught EXTERNAL Insteon DIM Result') when 0x24; log('Caught EXTERNAL Insteon DO EE READ') when 0x28; log('Caught EXTERNAL Insteon SET ADDRESS MSB') when 0x29; log('Caught EXTERNAL Insteon POKE') when 0x2A; log('Caught EXTERNAL Insteon POKE EXTENDED') when 0x2B; log('Caught EXTERNAL Insteon PEEK') when 0x2C; log('Caught EXTERNAL Insteon PEEK INTERNAL') when 0x2D; log('Caught EXTERNAL Insteon POKE INTERNAL') else log('Unknown EXTERNAL Insteon Command.') end end end ### Support Routine for EZToDCE def processACK(param) #log('In ProcessACK: Param7:' + param['Parameter7']) #log('CurrentCmd=' + $currentcmd.to_s) case param['Parameter7'].hex #Received an ack to THIS command when 0x1 #Assign to Group log('Got Assign to Group ACK') $currentcmd = 0x01 $cmdqueue[0]['Command'] = 'InsStdMsg' #processDeviceInfo(param) #cmdComplete when 0x2 #Delete from Group when 0x10 # PING log('Got PING ACK') #cmdComplete $currentcmd = 0x1 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x11 #ON $currentcmd = 0x11 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x13 #OFF $currentcmd = 0x13 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x6A #Thermostat Zone Command $currentcmd = 0x6A $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x6B #Thermostat Control Command $currentcmd = 0x6B $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x6C #Thermostat Cool Command $currentcmd = 0x6C $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x6D #Thermostat Cool Command $currentcmd = 0x6D $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x15 #Bright $currentcmd = 0x15 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x16 #DIM $currentcmd = 0x16 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x17 #Start Manual Change when 0x18 #Stop Manual Change when 0x19 #Status Request # Status Request Acked - get ready for InsStdMsg $currentcmd = 0x19 # change cmd to reflect InsStdMsg $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x24 log('Caught ACK for Insteon DO EE READ') $currentcmd = 0x24 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x28 log('Caught ACK for Insteon SET ADDRESS MSB') $currentcmd = 0x28 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x29 log('Caught ACK for Insteon POKE') $currentcmd = 0x29 $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x2A log('Caught ACK for Insteon POKE EXTENDED') $currentcmd = 0x2A $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x2B #log('Caught ACK for Insteon PEEK') $currentcmd = 0x2B $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x2C log('Caught ACK for Insteon PEEK INTERNAL') $currentcmd = 0x2C $cmdqueue[0]['Command'] = 'InsStdMsg' when 0x2D log('Caught ACK for Insteon POKE INTERNAL') $currentcmd = 0x2D $cmdqueue[0]['Command'] = 'InsStdMsg' else log('Unknown Insteon Cmd1') end end def checkPeekData(param) $remoteLinkRecord += param['Parameter11'].hex.chr log('CURRENT REMOTE RECORD IS:') debug($remoteLinkRecord) if $remoteLinkRecord.length == 8 log('REMOTE RECORD COMPLETE!') processRemoteRecord(param) $remoteLinkRecord = '' end end def processRemoteRecord(param) #have to find MY address insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = padhex(insHb) + "." + padhex(insMb) + "." + padhex(insLb) log('Processing remote Record below:') @flags = "\nFrom Device:" + insID + "\nFlags:\n" if ($remoteLinkRecord[0] & 0x02) == 0x02 # High water mark @flags += "Not the last record\n" else @flags += "This IS the last record\n" end if ($remoteLinkRecord[0] & 0x80) == 0x80 # Record is in use @flags += "Record In Use\n" if ($remoteLinkRecord[0] & 0x40) == 0x40 # Controller/Responder @flags += "I am a Controller of " else @flags += "I am a Responder of " end @insteonID = padhex("%X" %$remoteLinkRecord[2]) + '.' @insteonID += padhex("%X" %$remoteLinkRecord[3]) + '.' @insteonID += padhex("%X" %$remoteLinkRecord[4]) @group = "%X" %$remoteLinkRecord[1] @flags += @insteonID + " Group:" + @group @work = padhex("%X" %$remoteLinkRecord[0]) #Control byte @work += padhex("%X" %$remoteLinkRecord[1]) # Group @work += padhex("%X" %$remoteLinkRecord[2]) # ID HB @work += padhex("%X" %$remoteLinkRecord[3]) # ID MB @work += padhex("%X" %$remoteLinkRecord[4]) # ID LB @work += padhex("%X" %$remoteLinkRecord[5]) # Data1 @work += padhex("%X" %$remoteLinkRecord[6]) # Data2 @work += padhex("%X" %$remoteLinkRecord[7]) # Data3 log('adding to:' + insID) log('Value:' + @work) $childdatabases[insID] << @work #add it to the database # log('Current Database:' + $childdatabases.inspect) #now to save the database to configuration. savechilddatabases(insID) # Now to check to see if the child exists as a record if $childdatabases[@insteonID] == nil log('InsteonID is NEW, adding Child database entry') $childdatabases[@insteonID] = ['****************'] $rerun = true sendAddtoPLM(@insteonID) sendPing(@insteonID) else log('InsteonID:' + @insteonID.to_s + 'seems to exist in child databases') log('CDB:' + $childdatabases.inspect) end else @flags += "Record NOT in use\n" end log($aqua + @flags + $grey) log2(@flags) if ($remoteLinkRecord[0] & 0x02) == 0x02 sendRemoteGetNext(insID) end end def savechilddatabases(insteonID) #This takes the $childdatabase hash+array and encodes it to # save it as a string. @work = '' #log($yellow + 'SaveChildDatabases::nitems:' + $childdatabases[insteonID].nitems.to_s) #log($childdatabases[insteonID].inspect + $grey) $childdatabases[insteonID].each{|record| @work += record } #now to save the string... setdeviceconfig(insteonID, @work) end def sendPing(insteonID) insID = insteonID.split('.') param = {'Command' => 'SndIns', 'Parameter1' => insID[0], 'Parameter2' => insID[1], 'Parameter3' => insID[2], 'Parameter4' => '0F', 'Parameter5' => '10', #ID Request 'Parameter6' => '00'} $cmdqueue << param log('PING Sent!') end def getdevicetemplate(cat, subcat) log('Entered getdevicetemplate, Cat=' + cat.to_s + ', subcat = ' + subcat.to_s) @templid = 0 case cat.hex when 0x0 # Generalized Controllers case subcat.hex when 0x04; log('Found ControLinc [2430]') when 0x05; log('Found RemoteLinc [2440]') when 0x06; log('Found Icon Tabletop Controller [2830]') when 0x09; log('Found SignaLinc RF Signal Enhancer [2442]') when 0x0A; log('Found Balboa Instruments Poolux LCD Controller') when 0x0B; log('Found Access Point [2443]') when 0x0C; log('Found IES Color Touchscreen') end when 0x01 # Dimmable Lighting Control # all these devices are associated with Template 38 # Light Switch (dimmable) @templid = 38 case subcat.hex when 0x00; log('Found LampLinc V2 [2456D3]') when 0x01; log('Found SwitchLinc V2 Dimmer 600W [2476D]') when 0x02; log('Found In-LineLinc Dimmer [2475D]') when 0x03; log('Found Icon Switch Dimmer [2876D]') when 0x04; log('Found SwitchLinc V2 Dimmer 1000W [2476DH]') when 0x06; log('Found LampLinc 2-pin [2456D2]') when 0x07; log('Found Icon LampLinc V2 2-pin [2456D2]') when 0x09; log('Found KeypadLinc Dimmer [2486D]') when 0x0A; log('Found Icon In-Wall Controller [2886D]') when 0x0D; log('Found SocketLinc [2454D]') when 0x13; log('Found Icon SwitchLinc Dimmer for Lixar/Bell Canada [2676D-B]') when 0x17; log('Found ToggleLinc Dimmer [2466D]') end when 0x02 # Switched Lighting Control # all these devices are associated with Template 37 # Light Switch (ON/OFF) @templid = 37 case subcat.hex when 0x09; log('Found ApplianceLinc [2456S3]') when 0x0A; log('Found SwitchLinc Relay [2476S]') when 0x0B; log('Found Icon On Off Switch [2876S]') when 0x0C; log('Found Icon Appliance Adapter [2856S3]') when 0x0D; log('Found ToggleLinc Relay [2466S]') when 0x0E; log('Found Switchlinc Relay Countdown Timer [2476ST]') when 0x10; log('Found In-LineLinc Relay [2475D]') when 0x13; log('Found Icon SwitchLinc Relay for Lixar/Bell Canada [2676R-B]') end when 0x03 # Network Bridges case subcat.hex when 0x01; log('Found PowerLinc Serial [2414S]') when 0x02; log('Found PowerLinc USB [2414U]') when 0x03; log('Found Icon PowerLinc Serial [2814S]') when 0x04; log('Found Icon PowerLinc USB [2814U]') when 0x05; log('Found Smartlabs Power Line Modem Serial [2412S]') end when 0x04 # Irrigation Control # all these devices are associated with Template 1780 # Standard Irrigation Sprinkler @templid = 1780 case subcat.hex when 0x00; log('Found Simplehomenet EZRain1 Sprinkler Controller') end when 0x05 # Climate Control case subcat.hex when 0x00; log('Found Broan SMSC080 Exhaust Fan') when 0x01; log('Found Simplehomenet EZTherm') when 0x02; log('Found Broan SMSC110 Exhaust Fan') when 0x03 log('Found Venstar RF Thermostat Module') @templid = 2198 #Set Template when 0x04; log('Found Simplehomenet EZStat Thermostat') end when 0x06 # Pool and Spa Control case subcat.hex when 0x00; log('Found Simplehomenet EZPool') end when 0x07 # Sensors and Actuators case subcat.hex when 0x00 end when 0x08 # Home Entertainment case subcat.hex when 0x00 end when 0x09 # Energy Management case subcat.hex when 0x00 end when 0x0A # Built-In Appliance Control case subcat.hex when 0x00 end when 0x0B # Plumbing case subcat.hex when 0x00 end when 0x0C # Communication case subcat.hex when 0x00 end when 0x0D # Computer Control case subcat.hex when 0x00 end when 0x0E # Window Coverings case subcat.hex when 0x00 end when 0x0F # Access Control case subcat.hex when 0x00 end when 0x10 # Security, Health, and Safety when 0x11 # Surveillance when 0x12 # Automotive when 0x13 # Pet care when 0x14 # Toys when 0x15 # Timekeeping when 0x16 # Holiday end return @templid end def processDeviceInfo(param) ### temporary ### 12-24-07 Adding Device Template compatibility.. #have to find MY address insHb = param['Parameter3'] # From insMb = param['Parameter4'] insLb = param['Parameter5'] insID = padhex(insHb) + "." + padhex(insMb) + "." + padhex(insLb) #set the devicecat and device subcat in the childdatabases # 0-1 Device Category # 2-3 Device SubCategory # 4-5 Device Firmware log('proccessDeviceInfo:Insteon ID' + insID) $childdatabases[insID][0][0..1] = param['Parameter6'] $childdatabases[insID][0][2..3] = param['Parameter7'] $childdatabases[insID][0][4..5] = param['Parameter8'] savechilddatabases(insID) log('InsteonID: ' + insID) #log('Child Config AFTER update:' + $childdatabases[insID][0].to_s) log($yellow) @template = getdevicetemplate(param['Parameter6'], param['Parameter7']) $devicetemplate[insID] = @template log('Template ID:' + @template.to_s) ### eventually, open a XML configuration script? ### or read saved data from mysql? ### most likely save this information to sql with device. ### eventually, IPKDB will be available to ping. log('for Insteon ID:' + insID) log($grey) end def recvComplete # Clears the wait flag, but does not remove a command from the queue $wAIT = false log($green + "Receive Completed. Checking command queue" + $grey) if $cmdqueue.nitems > 0 then log("Queue:" + $aqua + $cmdqueue.nitems.to_s + $grey + " : executing next command") SndIns() else log($yellow + 'Queue Empty.' + $grey) if $rerun == true log('RERUN=TRUE, RESTARTING') $rerun = false mainRestart() else log('RERUN Not needed. Checking if reported..') #report Child devices here. if $reported == false log('Reporting Child Devices') @work = "" $childdatabases.each_key{ |insteonID| log('Child:' + insteonID) log('Config:' + $childdatabases[insteonID].inspect) @template = $devicetemplate[insteonID] @work += insteonID + "\t\t\t" + @template.to_s + "\t\n" } log(@work) cmd = Command.new(device_.devid_, -1001, 1, 2, 54) cmd.params_[13] = @work SendCommand(cmd) $reported = true else log('report not needed') end end end end def removecurrentcommand #get the current child log('in RemoveCurrentCommand') log('Current Command:' + $cmdqueue[0].inspect) #id is in param123 @id = $cmdqueue[0]['Parameter1'] @id += '.' + $cmdqueue[0]['Parameter2'] @id += '.' + $cmdqueue[0]['Parameter3'] log('ID=' + @id) #now to remove from child and PLM databases removefromchild(@id) removefromplm(@id) cmdComplete end def cmdComplete # Clears the wait flag, and removes the command from the queue. $wAIT = false $resetNext = 0 $cmdqueue.delete_at(0) # now that THAT command is completed, check to see if there is # another command ready to transmit. log($green + "Command Completed." + $grey) end def checkWait(param) #Checks for response from current command. if $cmdqueue[0] != nil if $wAIT == true #log('CW:waiting for command to complete') else #log('CW:reports clear') end else log('------:)----checkWait: command queue is emtpy') if $wAIT == true #this should never happen log('------:(XXX-CheckWait: TRUE') end end end def plmparse(value) #THIS ROUTINE REPLACES parsestring() #this routine will PARSE the incoming stream into valid messages # value is the complete command param = {} #here is a special case, the PLM seems to lock up. if value == 0x15.chr log('The PLM stopped responding') log('Please unplug it, and plug it back in') log('and do a quick reload router.') end while value.length > 2 case value[1] when 0x62 # Special case, need to look at flags if (value[5] & 0x10) == 0x10 # check for extended flag cmdlen = 23 else cmdlen = 9 end param['Response'] = 'SndIns' when 0x50; cmdlen = 11; param['Response'] = 'InsStdMsg' when 0x51; cmdlen = 25; param['Response'] = 'InsExtMsg' when 0x68; cmdlen = 4 #Set Insteon ACK Message Byte when 0x71; cmdlen = 5 #Set Insteon ACK Message Two Bytes when 0x70; cmdlen = 4 #Set Insteon NACK Message Byte when 0x63; cmdlen = 5; param['Response'] = 'SndX10' when 0x52; cmdlen = 4; param['Response'] = 'X10Msg' when 0x61; cmdlen = 6; param['Response'] = 'SndGrp' when 0x56; cmdlen = 7; param['Response'] = 'GrpEvntRpt' when 0x58; cmdlen = 3 #All-Link Cleanup Status Report when 0x64; cmdlen = 5; param['Response'] = 'StLnk' when 0x65; cmdlen = 3; param['Response'] = 'CancelLnk' when 0x53; cmdlen = 10; param['Response'] = 'InsLnkSts' when 0x69; cmdlen = 3; param['Response'] = 'GetLnk' when 0x6A; cmdlen = 3; param['Response'] = 'GetNext' when 0x6C; cmdlen = 3 #Get All-Link Record for Sender when 0x57; cmdlen = 10; param['Response'] = 'LnkData' when 0x6F; cmdlen = 12; param['Response'] = 'MngLnk' when 0x67; cmdlen = 3; param['Response'] = 'RstPLM' when 0x6B; cmdlen = 4; param['Response'] = 'SetCfg' when 0x60; cmdlen = 9; param['Response'] = 'GetVersion' when 0x66; cmdlen = 6 #Set Host Device Category when 0x72; cmdlen = 3 # RF Sleep when 0x54; cmdlen = 3; param['Response'] = 'BtnRpt' when 0x6D; cmdlen = 3; param['Response'] = 'LEDON' when 0x6E; cmdlen = 3; param['Response'] = 'LEDOFF' else log('ERROR IN PLMPARSE- Unknown Command') debug(value) return '' end #Now we know the length the command should be, see if we have it. #log('waiting for ' + cmdlen.to_s + ' characters...') #log('length of current input is ' + value.length.to_s) if value.length >= cmdlen #log('GOT whole response') #Yes, we have the whole command, Pack it in param for byt in 1..cmdlen param['Parameter' + byt.to_s] = padhex("%X" %value[byt - 1]) end #now remove it from the string.. value = value.slice(cmdlen, value.length - cmdlen) #Send it off for parsing #log('Sending to EZToDCE:' + param.inspect.to_s) EZToDCE(param) else #log('Still waiting...') #no, we have NOT received the whole command. end end return value 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 PLM command for SndIns if $wAIT == false #log('SndIns:currentcmd=' + $currentcmd.to_s) if $cmdqueue.nitems > 0 log("SndIns:Queue:" + $aqua + $cmdqueue.nitems.to_s + $grey) #log('SndIns:' + $cmdqueue.inspect) param = $cmdqueue[0] ### have to figure out the command byte 2 here work = '02'.hex.chr + plmcommand(param) ### PLM command compilation for loop in 2..param.keys.nitems @dummy = param['Parameter' + (loop - 1).to_s].to_s work+= @dummy.hex.chr end conn_.Reconnect() debugout(work) conn_.Send(work) #sleep 0.1 $wAIT = TRUE else log($yellow + 'Queue Empty.' + $grey) if $rerun == true log('RERUN=TRUE, RESTARTING') $rerun = false mainRestart() else log('RERUN Not needed') if $reported == false log('Reporting Child Devices') @work = "" $childdatabases.each_key{ |insteonID| log('Child:' + insteonID) log('Config:' + $childdatabases[insteonID].inspect) @template = $devicetemplate[insteonID] @work += insteonID + "\t\t\t" + @template.to_s + "\t\n" } log(@work) cmd = Command.new(device_.devid_, -1001, 1, 2, 54) cmd.params_[13] = @work SendCommand(cmd) $reported = true else log('report not needed') end end end 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 plmcommand(param) ### this returns the proper Byte2 for the command. case param['Command'] when 'GetVersion'; return 0x60.chr when 'SndIns'; return 0x62.chr when 'SndGrp'; return 0x61.chr when 'SndX10'; return 0x63.chr when 'GetLnk'; return 0x69.chr when 'GetNext'; return 0x6A.chr when 'BtnRpt'; return 0x54.chr when 'GetCfg'; return 0x73.chr when 'StLnk'; return 0x64.chr when 'CancelLnk'; return 0x65.chr when 'MngLnk'; return 0x6F.chr when 'RstPLM'; return 0x67.chr when 'SetCfg'; return 0x6B.chr when 'LEDON'; return 0x6D.chr when 'LEDOFF'; return 0x6E.chr ## hack when 'InsStdMsg' log('ERROR:PLMCommand encountered a COMMAND of INSSTDMSG') break return 0x62.chr end end def debug(text) work = 'DEBUG:' for c in 1..text.length work += padhex("%X" %text[c-1]) + ' ' end log($yellow + work + "Length:" + text.length.to_s + $grey) end def debugout(text) work = 'out:' for c in 1..text.length work += padhex("%X" %text[c-1]) + ' ' end log($green + work + "Length:" + text.length.to_s + $grey) end def debugin(text) work = 'IN:' for c in 1..text.length work += padhex("%X" %text[c-1]) + ' ' end log($red + work + "Length:" + text.length.to_s + $grey) 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.55)).to_i end def hextopercent(level) return ((level.hex.to_i / 2.55)).to_i end def hextoTempurature(degree) #Thermostat change hex to tempurature return ((degree.hex.to_i / 2)).to_i end def Tempuraturetohex (degree) #Thermostat Cahnge tempurature to hex return ((degree.to_1 * 2)).hex end def log(line) $log = File.open("/var/log/pluto/" + device_.devid_.to_s + "_Generic_Serial_Device.log", "a") $log.puts "(***):" + line.to_s $log.close end def log2(line) #this will send a message out the the orbiters.. #/usr/pluto/bin/MessageSend localhost 0 20 1 809 9 "Text to Display" 70 "alert" 182 "30" 251 "??" cmd = Command.new(device_.devid_, -1000, 1, 1, 809) cmd.params_[9] = line #text to display cmd.params_[70] = 'PLMMessage' #Token cmd.params_[182] = '10' #Timeout in seconds cmd.params_[251] = '??' SendCommand(cmd) end def checkChildRecordsinPLM() log('Entered CheckChildRecordsinPLM') # log('In CheckChildRecordsinPLM') # time to verify all children are in the PLM # # log('Total PLM Records:' + $plmdatabase.nitems.to_s) $plmdatabase.each{|record| log('Record: = '+ getIIDfromRecord(record) + ' Group:' + getGroupfromRecord(record)) log('checking to see if it needs to be added as a child...') if existsinchild(getIIDfromRecord(record)) == false log(getIIDfromRecord(record) + ' needs to be added to the child database') addtochild(getIIDfromRecord(record)) end } $childdatabases.each_key {|child| if existsinplm(child) == false log(child + ' needs to be added to PLM') sendAddtoPLM(child) else log(child + ' exists in PLM') end #now to scan the childs database for record in 1..($childdatabases[child].nitems - 1) @test = $childdatabases[child][record] if existsinplm(getIIDfromRecord(@test)) == false log(getIIDfromRecord(@test) + ' needs to be added to PLM') sendAddtoPLM(getIIDfromRecord(@test)) else log(getIIDfromRecord(@test) + ' exists in PLM') end #Also check to see if it needs to be added in the childdatabases end } end def existsinplm(insteonid) result = false $plmdatabase.each{|record| #log(insteonid + '==' + getIIDfromRecord(record)) if insteonid == getIIDfromRecord(record) result = true end } return result end def existsinchild(insteonid) log('ExistsinChild:InsteonID:' + insteonid) result = false $childdatabases.each_key{|record| if insteonid == record result = true end } log('ExistsinChild result:FALSE') if result == false log('ExistsinChild result:TRUE') if result == true return result end def addtochild(insteonID) log('addtochild Routne called') log('Adding ' + insteonID + ' to the child database...') if insteonID.length == 2 then log('Child is X10') $state[insteonID] = 0 else log('Child is Insteon') $childdatabases[insteonID] = ['****************'] sendPing(insteonID) $rerun = true end end def removefromchild(insteonID) log('Removing ' + insteonID + ' from child database') $childdatabases.delete(insteonID) $state.delete(insteonID) end def removefromplm(insteonID) log('Removing from plm') $plmdatabase.each{|record| #log(insteonid + '==' + getIIDfromRecord(record)) if insteonID == getIIDfromRecord(record) debug(record) log('Found Record, Deleting') $plmdatabase.delete(record) #now, we have to remove it from the device. param = {'Command' =>'MngLnk', 'Parameter1' => '80', #DELETE 'Parameter2' => record[0..1], #control byte 'Parameter3' => record[2..3], #group 'Parameter4' => record[4..5],#HB 'Parameter5' => record[6..7],#MB 'Parameter6' => record[8..9],#LB 'Parameter7' => record[10..11],#data1 'Parameter8' => record[12..13],#data2 'Parameter9' => record[14..15] #data3 } log(param.inspect) $cmdqueue << param end } end def sendAddtoPLM(insteonID) log('Adding ' + insteonID + ' to the PLM database...') #This adds a record into the PLM @insID = insteonID.split('.') param = {'Command' => 'MngLnk', 'Parameter1' => '40', #control code -- add new record as Controller 'Parameter2' => 'C2', #All Link Record Flags AKA Record Control Byte 'Parameter3' => '01', #All Link Group 'Parameter4' => @insID[0], #HB 'Parameter5' => @insID[1], #MB 'Parameter6' => @insID[2], #LB 'Parameter7' => '01', #Link Data 1 ON-Level 'Parameter8' => '01', #Link Data 2 Ramp Rate 'Parameter9' => 'FF'} #Link Data 3 not used if $wAIT == true $cmdqueue.insert(1, param) else $cmdqueue.insert(0, param) end SndIns() end def getIIDfromRecord(recordstring) #this extracts the insteonID string from the record. #log('getIIDfromRecord::recordstring:' + recordstring) @idhb = recordstring[4..5] @idmb = recordstring[6..7] @idlb = recordstring[8..9] @result = @idhb + '.' + @idmb + '.' +@idlb #log('GetIIDfromRecord: Found ID:' + @result) return @result end def processBroadcastMessage(param) #search the child databases for responders, #and fire COMMANDS for each responder. 06Feb08 #and fire events for each responder.XXXXXXXXXXXXX #Message flag is in parameter9 Group command 0xCx (All-Link Broadcast Message Pg 42.) #Group is in parameter8 #From InsteonID is parameters 3, 4, 5 group = param['Parameter8'] from = padhex(param['Parameter3']) + '.' from += padhex(param['Parameter4']) + '.' from += padhex(param['Parameter5']) log('Looking for ' + from + ' Group:' + group) log('Showing Parameter10:' + param['Parameter10'].to_s) #Ok, now have to search child databases for from AND group AND responder $childdatabases.each_key{|child| #log('Searching:' + child) for rec in 1..($childdatabases[child].nitems - 1) record = $childdatabases[child][rec] if getIIDfromRecord(record) == from # First, look for Insteon ID #log('Found ID') if getGroupfromRecord(record) == group #next, Group #log('Found Group') if isResponderRecord(record) # is a responder? #log('Found Responder') #figure out the child devicenum from = $children[child] #figure out the command case param['Parameter10'].hex when 0x11 #on reportStatus(from, 100) when 0x13 #off reportStatus(from, 0) when 0x6B # Thermostat Command On/OFF/AUTO case param['Parameter11'].to_s when '09' #status to OFF #need to set current temp reportStatus(from, 0) else #check thermostat for state and update and set current temp #reportStatus(from, 100) end when 0x6C # Thermostat Command Cool Point tempurature =param['Parameter11'] /2 #temp in hex need to devide by 2 = current cool point #reportStatus(from,tempurature) when 0x6D# Thermostat Command Heat Point tempurature =param['Parameter11'] /2 #temp in hex need to devide by 2 = current heat point #reportStatus(from,tempurature) when 0x17 #dim/brighten -ignore level = 0 when 0x18 # STOP dim/brighten - sendgetstatus level = 0 sendGetChildStatus(child) else level = 0 log('Command is other than ON/OFF/Dim/Brighten') end end end end end } end def reportStatus(from, level) log('From:' + from.to_s) #shows child id log('current State:' + $state[from].to_s) log('Wanted State:' + level.to_s) case $state[from] when 0 if level >=1 cmd = Command.new(from, from, 1, 1, 192) #on cmd.params_[120] = "1" SendCommand(cmd) cmd = Command.new(from, from, 1, 1, 184) cmd.params_[76] = level.to_s cmd.params_[120] = "1" SendCommand(cmd) end when 100 if level >= 1 cmd = Command.new(from, from, 1, 1, 184) cmd.params_[76] = level.to_s cmd.params_[120] = "1" SendCommand(cmd) else cmd = Command.new(from, from, 1, 1, 193) # off cmd.params_[120] = "1" SendCommand(cmd) end else if level == 100 cmd = Command.new(from, from, 1, 1, 193) #off cmd.params_[120] = "1" SendCommand(cmd) cmd = Command.new(from, from, 1, 1, 192) # on cmd.params_[120] = "1" SendCommand(cmd) end cmd = Command.new(from, from, 1, 1, 184) #SetLevel cmd.params_[76] = level.to_s cmd.params_[120] = "1" SendCommand(cmd) end log('ReportStatus: device:' + from.to_s + ' Status:' + level.to_s) $state[from] = level end def isResponderRecord(recordstring) work = recordstring[0..1].hex if (work & 0x40) == 0x40 #check bit 6 result = false #signifies Controller record else result = true #signifies Responder record end return result end def getGroupfromRecord(recordstring) #this extracts the GROUP from the record. if recordstring == nil return '00' else return recordstring[2..3] end end def getdeltafromconfig(insteonID) #This returns the delta from the child. @work = $childdatabases[insteonID][0] # the settings stored in [0] if @work == nil return '00' else return @work[6..7] end end def sendGetChildStatus(insteonID) #log('sendGetChildStatus Called') if insteonID.length != 2 #X10 device @insID = insteonID.split('.') param = {'Command' => 'SndIns', 'Parameter1' => @insID[0], 'Parameter2' => @insID[1], 'Parameter3' => @insID[2], 'Parameter4' => '0F', #flags 'Parameter5' => '19', #Status Request 'Parameter6' => '00'} #not used. $cmdqueue << param SndIns() #Returned response will have cmd1 = DBDelta #Returned response will have cmd2 = ON-Level else log('X10 does not report status') end end def islast(record) #high water mark return false if (record[0..1].hex & 0x02) == 0x02 return true end def isinuse(record) return true if (record[0..1].hex & 0x80) == 0x80 return false end def iscontroller(record) return true if (record[0..1].hex & 0x40) == 0x40 return false end def group(record) return record[2..3] end def remoteid(record) @insteonID = record[4..5] + '.' @insteonID += record[6..7] + '.' @insteonID += record[8..9] return @insteonID end def findresponderrecord(masterid, slaveid, groupid) # log(masterid + ':' + slaveid + ':' + groupid) $childdatabases[slaveid].each{|check| # log('Record:' + check.to_s) if iscontroller(check.to_s) == false #responder record # log('found responder record') # log('remoteid:' + remoteid(check.to_s)) if remoteid(check.to_s) == masterid # found # log('Found Controller ID in responder record') if group(check.to_s) == groupid # log('Group Matches') #found group return true end end end } return false end def findcontrollerrecord(masterid, slaveid, groupid) # log(masterid + ':' + slaveid + ':' + groupid) $childdatabases[masterid].each{|check| # log('Record:' + check.to_s) if iscontroller(check.to_s) == true #controller # log('found controller record') if remoteid(check.to_s) == slaveid # found # log('found Responder ID in Controller record') if group(check.to_s) == groupid # log('Group Matches') #found group return true end end end } return false end # time to define a structure to save the raw data in hex # starts at [0] # Bytes Meaning # 0-1 Device Category # 2-3 Device SubCategory # 4-5 Device Firmware # 6-7 Database Delta # 8-9 reserved # 10-11 reserved # 12-13 reserved # 14-15 reserved ###### First database record below (in same format its read from the device) ###### This is the same format as an ALL-Link Record Response from the PLM ###### (0x57) bytes 3..10 # 16-17 record control byte # 18-19 Group # 20-21 ID HB # 22-23 ID MB # 24-25 ID LB # 26-27 Link Specific Data1 # 28-29 Link Specific Data2 # 30-31 Link Specific Data3 ###### # 32-47 next database record...