Changeset 56


Ignore:
Timestamp:
2013-01-27 16:19:15 (12 years ago)
Author:
nlrb
Message:

Improvements for auto-enrollment

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/L_Powermax.lua

    r55 r56  
    1212local Queue = {} 
    1313function Queue.new() 
    14     return {first = 0, last = -1} 
     14   return {first = 0, last = -1} 
    1515end 
    1616 
    1717function Queue.pushright(list, value) 
    18     local last = list.last + 1 
    19     list.last = last 
    20     list[last] = value 
     18   local last = list.last + 1 
     19   list.last = last 
     20   list[last] = value 
    2121end 
    2222     
     
    7171local pmEventCnt 
    7272-- POWERLINK -- 
     73local pmStarting = true 
    7374local pmDownloadCode = "VP" -- Vera Powerlink 
    7475local pmPowerlinkMode = false 
     
    8384 
    8485local pmPanelInit_t = { 
    85     { "PluginVersion", PLUGIN_VERSION, false }, -- false: update 
     86   { "PluginVersion", PLUGIN_VERSION, false }, -- false: update 
    8687   { "MotionOffDelay", pmMotionOffDelay, true }, -- true: create only 
    8788   { "PluginLanguage", pmLang, true }, 
    88     { "PluginDebug", "0", true }, 
     89   { "PluginDebug", "0", true }, 
    8990   { "ForceStandard", "0", true }, 
    9091   { "AutoCreate", "1", true }, 
     
    139140local pmSendMsg_t = { 
    140141   MSG_INIT      = { string.char(0xAB, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43), nil }, 
     142   MSG_CLEAR     = { string.char(0xAB, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43), 0xA5 }, 
    141143   MSG_RESTORE   = { string.char(0xAB, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43), 0xA5 }, 
    142144   MSG_ENROLL    = { string.char(0xAB, 0x0A, 0x00, 0x00) .. pmDownloadCode .. string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x43), nil }, 
     
    404406-- Update a system variable only if the value will change 
    405407function updateIfNeeded(sid, var, newVal, id, createOnly) 
    406     local curVal = luup.variable_get(sid, var, id) 
     408   local curVal = luup.variable_get(sid, var, id) 
    407409   local valUpdate = (curVal == nil) or ((createOnly ~= true) and (curVal ~= tostring(newVal)) or false) 
    408     if (valUpdate == true) then 
    409         luup.variable_set(sid, var, newVal, id) 
    410         return true 
    411     end 
    412     return false 
     410   if (valUpdate == true) then 
     411      luup.variable_set(sid, var, newVal, id) 
     412      return true 
     413   end 
     414   return false 
    413415end 
    414416 
    415417-- Find child device (Taken from GE Caddx Panel but comes originally from guessed) 
    416418function findChild(deviceId, label) 
    417     for k, v in pairs(luup.devices) do 
    418        if (v.device_num_parent == deviceId and v.id == label) then 
    419            return k 
    420        end 
    421     end 
     419   for k, v in pairs(luup.devices) do 
     420      if (v.device_num_parent == deviceId and v.id == label) then 
     421         return k 
     422      end 
     423   end 
    422424end 
    423425 
     
    445447-- Control debug to /var/log/cmh/LuaUPnP.log (taken from GE Caddx Panel) 
    446448function debug(s) 
    447     if (pmLogDebug) then 
    448        luup.log("POWERMAX: " .. s) 
    449     end 
     449   if (pmLogDebug) then 
     450      luup.log("POWERMAX: " .. s) 
     451   end 
    450452end 
    451453 
     
    512514-- Calculate CRC for PDU send to PowerMax  
    513515function pmCalcCRC(pdu) 
    514     local checksum = 0 
    515     local newPDU 
    516     local len = string.len(pdu) 
    517  
    518     assert(len >= 2) 
    519     for i = 2, (len - 2) do 
    520        checksum = checksum + tonumber(string.byte(pdu, i)) 
    521     end 
    522     checksum = 0xFF - (checksum % 0xFF) 
    523     if (checksum == 0xFF) then checksum = 0x00 end 
    524     newPDU = string.sub(pdu, 1, len - 2) .. string.char(checksum, 0x0A) 
    525     return newPDU 
     516   local checksum = 0 
     517   local newPDU 
     518   local len = string.len(pdu) 
     519 
     520   assert(len >= 2) 
     521   for i = 2, (len - 2) do 
     522      checksum = checksum + tonumber(string.byte(pdu, i)) 
     523   end 
     524   checksum = 0xFF - (checksum % 0xFF) 
     525   if (checksum == 0xFF) then checksum = 0x00 end 
     526   newPDU = string.sub(pdu, 1, len - 2) .. string.char(checksum, 0x0A) 
     527   return newPDU 
    526528end 
    527529 
    528530-- Check CRC in PDU received from PowerMax 
    529531function pmCheckCRC(pdu) 
    530     local checksum = 0 
    531     local len = string.len(pdu) 
    532  
    533     assert(len >= 2) 
    534     for i = 2, (len - 2) do 
    535        checksum = checksum + tonumber(string.byte(pdu, i)) 
    536     end 
    537     checksum = 0xFF - (checksum % 0xFF) 
    538     if (checksum == 0xFF) then checksum = 0x00 end 
     532   local checksum = 0 
     533   local len = string.len(pdu) 
     534 
     535   assert(len >= 2) 
     536   for i = 2, (len - 2) do 
     537      checksum = checksum + tonumber(string.byte(pdu, i)) 
     538   end 
     539   checksum = 0xFF - (checksum % 0xFF) 
     540   if (checksum == 0xFF) then checksum = 0x00 end 
    539541   local got = tonumber(string.byte(pdu, len - 1)) 
    540542   if (checksum == got) then 
     
    553555-- Convert PDU bytes to a string for logging  
    554556function pmPduToString(pdu) 
    555     local PDUstr = "" 
    556     for i = 1, string.len(pdu) do 
    557         PDUstr = PDUstr .. string.format("%02X ", string.byte(pdu, i)) 
    558     end 
    559     return PDUstr 
     557    local PDUstr = "" 
     558    for i = 1, string.len(pdu) do 
     559      PDUstr = PDUstr .. string.format("%02X ", string.byte(pdu, i)) 
     560    end 
     561    return PDUstr 
    560562end 
    561563 
     
    630632   -- Check if a tripped motion sensor has timed out 
    631633   for i = 1, 30 do 
    632         local sensor = pmSensorDev_t[i] 
     634      local sensor = pmSensorDev_t[i] 
    633635      if (sensor ~= nil) then 
    634636         local child = sensor['id'] 
     
    639641         end 
    640642      end 
    641     end 
     643   end 
    642644   -- Check Siren 
    643645   if (pmSirenActive ~= nil) and (now > pmSirenActive) then 
     
    647649      end 
    648650   end 
    649     luup.call_timer("pmIntervalCheck", 1, "20s", "", "") 
     651   luup.call_timer("pmIntervalCheck", 1, "20s", "", "") 
    650652end 
    651653 
     
    687689-- Initialises the panel, handlers etc. 
    688690function pmStartup(lul_device) 
    689     pmPanelDev = lul_device 
     691   pmPanelDev = lul_device 
    690692 
    691693   local exceptions = luup.variable_get(PANEL_SID, "CommExceptions", pmPanelDev) 
     
    705707   end 
    706708 
    707     luup.log("POWERMAX: starting ... device #" .. tostring(pmPanelDev), 10) 
     709   luup.log("POWERMAX: starting ... device #" .. tostring(pmPanelDev), 10) 
    708710 
    709711   for i = 1, #pmPanelInit_t do 
    710         updateIfNeeded(PANEL_SID, pmPanelInit_t[i][1], pmPanelInit_t[i][2], pmPanelDev, pmPanelInit_t[i][3]) 
     712      updateIfNeeded(PANEL_SID, pmPanelInit_t[i][1], pmPanelInit_t[i][2], pmPanelDev, pmPanelInit_t[i][3]) 
    711713   end 
    712714 
     
    718720   pmMotionOffDelay = tonumber(luup.variable_get(PANEL_SID, "MotionOffDelay", pmPanelDev), 10) 
    719721    
    720     if (luup.io.is_connected(pmPanelDev) == false) then 
    721         pmMessage("Please select the Serial Port for the PowerMax", 2) 
    722         return false 
    723     end 
     722   if (luup.io.is_connected(pmPanelDev) == false) then 
     723      pmMessage("Please select the Serial Port for the PowerMax", 2) 
     724      return false 
     725   end 
    724726 
    725727   -- Register all message handlers 
     
    740742   end 
    741743 
    742    pmSendMessage("MSG_INIT") 
     744   pmSendMessage("MSG_CLEAR") 
    743745   if (forceStandard == false) then 
    744746      pmStartDownload() 
     
    748750   end 
    749751    
    750     luup.call_timer("pmIntervalCheck", 1, "20s", "", "") 
     752   luup.call_timer("pmIntervalCheck", 1, "20s", "", "") 
    751753end 
    752754 
    753755-- pmGetPin: Convert a PIN given as string in the PIN PDU format as used in messages to powermax 
    754756function pmGetPin(pin)  
    755     local pinPDU 
    756  
    757     if (pin == "") or (pin == nil) or (string.len(pin) ~= 4) then 
     757   local pinPDU 
     758 
     759   if (pin == "") or (pin == nil) or (string.len(pin) ~= 4) then 
    758760      if (pmPowerlinkMode == true) then 
    759761         return pmPincode_t[1], true 
     
    763765         return pinPDU, false 
    764766      end 
    765     end 
    766     pinPDU = string.char(tonumber(string.sub(pin, 1, 2), 16), tonumber(string.sub(pin, 3, 4), 16)) 
    767  
    768     return pinPDU, false 
     767   end 
     768   pinPDU = string.char(tonumber(string.sub(pin, 1, 2), 16), tonumber(string.sub(pin, 3, 4), 16)) 
     769 
     770   return pinPDU, false 
    769771end 
    770772 
     
    969971   end 
    970972 
    971     pmMessage("Adding zone devices", 4) 
     973   pmMessage("Adding zone devices", 4) 
    972974   -- Use variables if AutoCreate is false or not in Powerlink mode, otherwise use what we read in the settings 
    973975   local doorZones = doorZoneStr 
     
    10201022      end 
    10211023   end 
    1022      
     1024    
    10231025   -- Add PGM and X10 devices 
    1024     for i = 0, 15 do 
    1025         if (i == 0) then 
    1026             if (string.find(devices, "PGM")) then 
     1026   for i = 0, 15 do 
     1027      if (i == 0) then 
     1028         if (string.find(devices, "PGM")) then 
    10271029            pmCreateDevice(childDevices, "PGM", "Switch", "PGM") 
    1028             end 
    1029         else 
    1030             s = string.format("X%02d", i) 
     1030         end 
     1031      else 
     1032         s = string.format("X%02d", i) 
    10311033         local pos = string.find(devices, s) 
    1032             if (pos ~= nil) then 
     1034         if (pos ~= nil) then 
    10331035            local devInit 
    10341036            if (string.sub(devices, pos + 3, pos + 3) == "d") then 
     
    10371039               pmCreateDevice(childDevices, s, "Switch", x10_t[i], s) 
    10381040            end 
    1039             end 
    1040         end 
    1041         local x10_device = findChild(pmPanelDev, s) 
    1042         if (x10_device ~= nil) then 
     1041         end 
     1042      end 
     1043      local x10_device = findChild(pmPanelDev, s) 
     1044      if (x10_device ~= nil) then 
    10431045         x10_dev_nr = string.format("%04x", 2 ^ i) 
    10441046         updateIfNeeded(PANEL_SID, "X10DeviceNr", x10_dev_nr, x10_device, true) 
    1045         end 
    1046     end 
     1047      end 
     1048   end 
    10471049    
    10481050   -- Add sirens 
     
    10731075   luup.chdev.sync(pmPanelDev, childDevices) 
    10741076   pmSendMessage("MSG_STATUS") 
     1077   pmStarting = false 
    10751078   pmMessage("Ready for use", 2) 
    10761079end 
     
    11041107-- pmStartDownload (exposed as called with delay) 
    11051108function pmStartDownload(stuff) 
    1106    pmSendMessage("MSG_DOWNLOAD")    -- If we get a NACK, then the download code is not valid (not enrolled) 
     1109   pmStarting = true 
     1110   pmSendMessage("MSG_DOWNLOAD")   -- If we get a NACK, then the download code is not valid (not enrolled) 
    11071111   pmLastKeepAlive = os.time() 
    11081112end 
     
    11481152   end 
    11491153    
    1150     if (timeout == true) or (pmExpectedResponse == "") then -- we are ready to send 
     1154   if (timeout == true) or (pmExpectedResponse == "") then -- we are ready to send 
    11511155      -- Always expect an ACK (ACK send messages don't pass through here) 
    11521156      pmExpectedResponse = string.char(0x02) .. response 
     
    11611165      end 
    11621166      pmWaitingForResponse = os.time() 
    1163     else -- queue message 
    1164         Queue.pushright(pmOutgoingQueue, { outPdu, response }) 
    1165     end 
    1166     return true 
     1167   else -- queue message 
     1168      Queue.pushright(pmOutgoingQueue, { outPdu, response }) 
     1169   end 
     1170   return true 
    11671171end 
    11681172 
     
    11731177   local success 
    11741178    
    1175     if (pduLen == 0) then 
    1176         if (string.byte(data) == 0x0D) then -- preamble 
    1177             debug("start of new PDU detected") 
    1178             pmIncomingPdu = data 
     1179   if (pduLen == 0) then 
     1180      if (string.byte(data) == 0x0D) then -- preamble 
     1181         debug("start of new PDU detected") 
     1182         pmIncomingPdu = data 
    11791183      end 
    11801184   elseif (pduLen == 1) then 
     
    11831187      debug(string.format("Message %02X; pmIncomingPduLen = %d", string.byte(data), pmIncomingPduLen)) 
    11841188      pmIncomingPdu = pmIncomingPdu .. data 
    1185     elseif (pmIncomingPduLen == 0 and string.byte(data) == 0x0A) or (pduLen + 1 == pmIncomingPduLen) then -- postamble 
    1186         pmIncomingPdu = pmIncomingPdu .. data 
    1187         if (pmCheckCRC(pmIncomingPdu) == true) then 
     1189   elseif (pmIncomingPduLen == 0 and string.byte(data) == 0x0A) or (pduLen + 1 == pmIncomingPduLen) then -- postamble 
     1190      pmIncomingPdu = pmIncomingPdu .. data 
     1191      if (pmCheckCRC(pmIncomingPdu) == true) then 
    11881192         pmLastPDU = pmIncomingPdu 
    1189             local PDUstr = pmPduToString(pmIncomingPdu) 
     1193         local PDUstr = pmPduToString(pmIncomingPdu) 
    11901194         local msgType = string.byte(pmIncomingPdu, 2) 
    11911195         local msgType_t = pmReceiveMsg_t[msgType] 
    1192             debug(string.format("PDU received %s", PDUstr)) 
    1193             pmLogPdu(PDUstr, "<-PM-") 
     1196         debug(string.format("PDU received %s", PDUstr)) 
     1197         pmLogPdu(PDUstr, "<-PM-") 
    11941198         pmWaitingForResponse = os.time() 
    11951199          
     
    12351239         if (pmExpectedResponse == "") then 
    12361240            pmSendMessage(nil) 
    1237             end 
    1238             pmIncomingPdu = "" 
     1241         end 
     1242         pmIncomingPdu = "" 
    12391243      else -- CRC check failed 
    12401244         if (pmIncomingPduLen > 0) then 
     
    12521256         end 
    12531257      end 
    1254     else 
    1255         pmIncomingPdu = pmIncomingPdu .. data 
    1256     end 
    1257     return true 
     1258   else 
     1259      pmIncomingPdu = pmIncomingPdu .. data 
     1260   end 
     1261   return true 
    12581262end 
    12591263 
     
    12901294      luup.variable_set(PANEL_SID, "PowerlinkMode", "Standard", pmPanelDev) 
    12911295      pmMessage("Vera Powerlink not enrolled.", 2) 
    1292    end 
    1293    pmExpectedResponse = string.char(0x08) .. string.sub(pmExpectedResponse, 2) 
     1296      pmProcessSettings() 
     1297   end 
     1298   pmExpectedResponse = string.char(0x08) 
    12941299   return true 
    12951300end 
     
    14901495      updateIfNeeded(PARTITION_SID, "VendorStatusCode", string.format("%02X%02X", sysStatus, sysFlags), pmPartitionDev_t[1]) 
    14911496      updateIfNeeded(PARTITION_SID, "VendorStatusData", s, pmPartitionDev_t[1]) 
    1492         updateIfNeeded(PARTITION_SID, "ArmMode", armMode, pmPartitionDev_t[1]) 
    1493         updateIfNeeded(PARTITION_SID, "ArmModeNum", armModeNum, pmPartitionDev_t[1]) 
     1497      updateIfNeeded(PARTITION_SID, "ArmMode", armMode, pmPartitionDev_t[1]) 
     1498      updateIfNeeded(PARTITION_SID, "ArmModeNum", armModeNum, pmPartitionDev_t[1]) 
    14941499      updateIfNeeded(PARTITION_SID, "DetailedArmMode", (pmDetailedArmMode_t[sysStatus + 1] or "UNKNOWN"), pmPartitionDev_t[1]) 
    14951500      if (pmSensorShowBypass == false) then 
     
    15641569   if (subType == 0x03) then -- keepalive message 
    15651570      pmSendAck(0x02) 
     1571      if (pmStarting == false) and (pmPowerlinkMode == false) then 
     1572         debug("Got alive message while not in Powerlink mode; starting download") 
     1573         pmStartDownload() 
     1574      end 
    15661575      pmLastKeepAlive = os.time() 
    15671576      pmPowerlinkRetry = 0 
     
    15751584      pmSendAck(0x02) 
    15761585   elseif (subType == 0x0A and string.byte(pmIncomingPdu, 5) == 0x01) then 
    1577       debug("Enrolling PowerLink") 
     1586      debug("Enrolling Powerlink") 
     1587      pmWaitingForResponse = 0 -- make sure the message is sent right away; generate a timeout 
    15781588      pmSendMessage("MSG_ENROLL") 
    15791589      pmExpectedResponse = string.char(0xAB) .. pmExpectedResponse 
     
    16131623-- RequestQuickArmMode 
    16141624function RequestQuickArmMode(DetailedArmMode) 
    1615     debug("RequestQuickArmMode " .. (state or "N/A")) 
     1625   debug("RequestQuickArmMode " .. (state or "N/A")) 
    16161626 
    16171627   if (DetailedArmMode == "Stay") or (DetailedArmMode == "Armed") then 
     
    16231633   else 
    16241634      pmMessage("RequestQuickArmMode only possible for Arm or Stay.", 2) 
    1625     end 
     1635   end 
    16261636end 
    16271637 
     
    16521662-- SetTarget 
    16531663function SetTarget(device, DeviceID, newTargetValue) 
    1654     -- Two ways to call this function 
    1655     -- 1. Using lul_device (don't set 'DeviceID') 
    1656     -- 2. Setting 'DeviceID' to the X10 nr (e.g. 7 for X07) 
     1664   -- Two ways to call this function 
     1665   -- 1. Using lul_device (don't set 'DeviceID') 
     1666   -- 2. Setting 'DeviceID' to the X10 nr (e.g. 7 for X07) 
    16571667   if (DeviceID ~= nil) then 
    1658         local s = (DeviceID == 0) and "PGM" or string.format("X%02d", DeviceID) 
    1659         local child = findChild(pmPanelDev, s) 
    1660         if (child == nil) then 
    1661             debug(string.format("Unable to locate device X%02d", DeviceID)) 
    1662             return false 
    1663         else 
    1664             device = child 
    1665         end 
    1666     end 
    1667     local device_nr = luup.variable_get(PANEL_SID, "X10DeviceNr", device) 
     1668      local s = (DeviceID == 0) and "PGM" or string.format("X%02d", DeviceID) 
     1669      local child = findChild(pmPanelDev, s) 
     1670      if (child == nil) then 
     1671         debug(string.format("Unable to locate device X%02d", DeviceID)) 
     1672         return false 
     1673      else 
     1674         device = child 
     1675      end 
     1676   end 
     1677   local device_nr = luup.variable_get(PANEL_SID, "X10DeviceNr", device) 
    16681678  
    1669     if (device_nr ~= nil) then 
    1670        local onoff = newTargetValue or 0 
     1679   if (device_nr ~= nil) then 
     1680      local onoff = newTargetValue or 0 
    16711681      local x10dev = string.char(tonumber(string.sub(device_nr, 3, 4),16)) .. string.char(tonumber(string.sub(device_nr, 1, 2),16)) 
    1672        debug("Turn X10 device on/off (" .. onoff .. "/" ..  device_nr ..")") 
    1673        luup.variable_set(X10DEVICE_SID, "Target", onoff, device) 
     1682      debug("Turn X10 device on/off (" .. onoff .. "/" ..  device_nr ..")") 
     1683      luup.variable_set(X10DEVICE_SID, "Target", onoff, device) 
    16741684      pmSendMessage("MSG_X10PGM", { cmd = string.char(onoff), device = x10dev }) 
    1675         -- If it went OK, we will receive an A5 status from the PowerMax, which will update the X10 status 
    1676     end 
     1685      -- If it went OK, we will receive an A5 status from the PowerMax, which will update the X10 status 
     1686   end 
    16771687end 
    16781688 
     
    16891699-- SetLoadLevelTarget 
    16901700function SetLoadLevelTarget(device, newLoadlevelTarget) 
    1691     local device_nr = luup.variable_get(PANEL_SID, "X10DeviceNr", device) 
     1701   local device_nr = luup.variable_get(PANEL_SID, "X10DeviceNr", device) 
    16921702  
    1693     if (device_nr ~= nil) then 
     1703   if (device_nr ~= nil) then 
    16941704      local current = luup.variable_get(X10DEVICEDIM_SID, "LoadLevelTarget", device) or 0 
    1695        debug("Dimming X10 device (" .. newLoadlevelTarget .. "/" ..  device_nr ..")") 
     1705      debug("Dimming X10 device (" .. newLoadlevelTarget .. "/" ..  device_nr ..")") 
    16961706 
    16971707      local cmd = nil 
     
    17341744-- ToggleState 
    17351745function ToggleState(device) 
    1736     local lul_arguments = {} 
    1737     local onoff = luup.variable_get(X10DEVICE_SID, "Status", device) or 0 
    1738     lul_arguments["newTargetValue"] = 1 - onoff 
    1739     lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(X10DEVICE_SID, "SetTarget", lul_arguments, device) 
     1746   local lul_arguments = {} 
     1747   local onoff = luup.variable_get(X10DEVICE_SID, "Status", device) or 0 
     1748   lul_arguments["newTargetValue"] = 1 - onoff 
     1749   lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(X10DEVICE_SID, "SetTarget", lul_arguments, device) 
    17401750end 
    17411751 
    17421752-- GetEventLog 
    17431753function GetEventLog(device, PINCode) 
    1744     debug("GetEventLog") 
    1745     luup.variable_set(PANEL_SID, "EventLog", "", device) 
     1754   debug("GetEventLog") 
     1755   luup.variable_set(PANEL_SID, "EventLog", "", device) 
    17461756   pmSendMessage("MSG_EVENTLOG", { pin = pmGetPin(PINCode) }) 
    17471757end 
Note: See TracChangeset for help on using the changeset viewer.