- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
/I_ElkAlarmPanel1.lua
r20 r30 2 2 3 3 -- Flags 4 local DEBUG_MODE = true 5 local UPDATE_AT_STARTUP = true 4 local DEBUG_MODE = false 6 5 7 6 -- Constants 8 7 local VERSION = "1.0 alpha" 9 8 10 local PANEL_SID = "urn:micasaverde-com:serviceId:ElkAlarmPanel1" 11 local PARTITION_SID = "urn:micasaverde-com:serviceId:AlarmPartition2" 12 local SECURITY_SID = "urn:micasaverde-com:serviceId:SecuritySensor1" 13 14 local TASK_ERROR = 2 15 local TASK_ERROR_PERM = -2 16 local TASK_SUCCESS = 4 17 local TASK_BUSY = 1 18 19 local MAX_RETRIES = 3 9 local SID = { 10 PANEL = "urn:micasaverde-com:serviceId:ElkAlarmPanel1", 11 PARTITION = "urn:micasaverde-com:serviceId:AlarmPartition2", 12 SECURITY = "urn:micasaverde-com:serviceId:SecuritySensor1" 13 } 14 15 local TASK = { 16 ERROR = 2, 17 ERROR_PERM = -2, 18 SUCCESS = 4, 19 BUSY = 1 20 } 21 22 local MAX_RETRIES = 2 23 local MAX_READS = 3 20 24 21 25 -- Globals 22 local g_remoteArmEnabled = false23 local g_remoteDisarmEnabled = false24 local g_remotePanicEnabled = false25 26 26 local lug_device = nil 27 local g_errorMessage = nil 28 local g_pinCode = nil 27 local g_pinCodes = {} 29 28 local g_taskHandle = -1 30 29 31 30 local g_childDevices = { 32 partitions = {}, 33 zones = {}, 34 } 35 36 local log = luup.log 31 partitions = { 32 -- Members: 33 -- * device 34 -- * label 35 -- * zones 36 -- * armingStatus 37 -- * armUpState 38 -- * alarmState 39 }, 40 zones = { 41 -- Members: 42 -- * device 43 -- * label 44 -- * partition 45 -- * armed 46 -- * tripped 47 }, 48 } 49 50 local g_status = { 51 errorMessage = nil, 52 startup = false 53 } 54 55 local g_remote = { 56 armEnabled = false, 57 disarmEnabled = false, 58 panicEnabled = false 59 } 37 60 38 61 … … 46 69 ['2'] = "Voice only", 47 70 ['3'] = "Chime and voice" 48 }]]49 50 local EVENTS = {51 FIRE_ALARM = 1001,52 FIRE_SUPERVISORY_ALARM = 1002,53 BURGLAR_ALARM = 1003,54 MEDICAL_ALARM = 1004,55 POLICE_ALARM = 1005,56 AUX1_ALARM = 1006,57 AUX2_ALARM = 1007,58 CARBON_MONOXIDE_ALARM = 1008,59 EMERGENCY_ALARM = 1009,60 FREEZE_ALARM = 1010,61 GAS_ALARM = 1011,62 HEAT_ALARM = 1012,63 WATER_ALARM = 1013,64 ANY_ALARM = 1014,65 BURGLAR = 1015,66 MEDICAL = 1023,67 POLICE = 1031,68 AUX1 = 1039,69 AUX2 = 1047,70 CO = 1055,71 EMERGENCY = 1063,72 FREEZE = 1071,73 GAS = 1079,74 HEAT = 1087,75 WATER = 1095,76 ANY = 110377 }78 79 local TROUBLES = {80 "AC Fail Trouble",81 "Box Tamper Trouble",82 "Fail To Communicate Trouble",83 "EProm Memory Error Trouble",84 "Low Battery Control Trouble",85 "Transmitter Low Battery Trouble",86 "Over Current Trouble",87 "Telephone Fault Trouble",88 "N/A",89 "Output 2 Trouble",90 "Missing Keypad Trouble",91 "Zone Expander Trouble",92 "Output Expander Trouble",93 "N/A",94 "ELKRP Remote Access Trouble",95 "N/A",96 "Common Area Not Armed Trouble",97 "Flash Memory Error Trouble",98 "Security Alert Trouble",99 "Serial Port Expander Trouble",100 "Lost Transmitter Trouble",101 "GE Smoke CleanMe Trouble",102 "Ethernet Trouble",103 "N/A",104 "N/A",105 "N/A",106 "N/A",107 "N/A",108 "N/A",109 "N/A",110 "N/A",111 "Display Message In Keypad Line 1 Trouble",112 "Display Message In Keypad Line 2 Trouble",113 "Fire Trouble"114 }115 116 local ARMING_STATUSES = {117 ['0'] = "Disarmed",118 ['1'] = "Armed",119 ['2'] = "Stay",120 ['3'] = "StayInstant",121 ['4'] = "Night",122 ['5'] = "NightInstant",123 ['6'] = "Vacation"124 71 } 125 72 … … 132 79 ['5'] = "ForceArmed", 133 80 ['6'] = "ArmedWithBypass" 134 }135 136 local ALARM_STATES = {137 ['0'] = "None",138 ['1'] = "EntranceDelay",139 ['2'] = "AlarmAbortDelay",140 ['3'] = "FireAlarm",141 ['4'] = "MedicalAlarm",142 ['5'] = "PoliceAlarm",143 ['6'] = "BurglarAlarm",144 ['7'] = "Aux1Alarm",145 ['8'] = "Aux2Alarm",146 ['9'] = "Aux3Alarm", -- not used147 [':'] = "Aux4Alarm", -- not used148 [';'] = "CarbonMonoxideAlarm",149 ['<'] = "EmergencyAlarm",150 ['='] = "FreezeAlarm",151 ['>'] = "GasAlarm",152 ['?'] = "HeatAlarm",153 ['@'] = "WaterAlarm",154 ['A'] = "FireSupervisory",155 ['B'] = "VerifyFire"156 }157 158 local ZONE_STATUSES = {159 ['0'] = {"Normal", "Unconfigured"},160 ['1'] = {"Normal", "Open"},161 ['2'] = {"Normal", "EOL"},162 ['3'] = {"Normal", "Short"},163 ['4'] = nil,164 ['5'] = {"Trouble", "Open"},165 ['6'] = {"Trouble", "EOL"},166 ['7'] = {"Trouble", "Short"},167 ['8'] = nil,168 ['9'] = {"Violated", "Open"},169 ['A'] = {"Violated", "EOL"},170 ['B'] = {"Violated", "Short"},171 ['C'] = {"Bypassed", nil},172 ['D'] = {"Bypassed", "Open"},173 ['E'] = {"Bypassed", "EOL"},174 ['F'] = {"Bypassed", "Short"}175 }176 177 local LABEL_TYPES = {178 ["00"] = "Zone Name",179 ["01"] = "Area Name",180 ["02"] = "User Name",181 ["03"] = "Keypad Name",182 ["04"] = "Output Name",183 ["05"] = "Task Name",184 ["06"] = "Telephone Name",185 ["07"] = "Light Name",186 ["08"] = "Alarm Duration Name",187 ["09"] = "Custom Settings",188 ["10"] = "Counters Names",189 ["11"] = "Thermostat Names",190 ["12"] = "Function Key 1 Name",191 ["13"] = "Function Key 2 Name",192 ["14"] = "Function Key 3 Name",193 ["15"] = "Function Key 4 Name",194 ["16"] = "Function Key 5 Name",195 ["17"] = "Function Key 6 Name",196 ["18"] = "Audio Zone Name",197 ["19"] = "Audio Source Name"198 81 } 199 82 … … 237 120 ['T'] = "Intercom Key" 238 121 } 122 ]] 123 124 local EVENTS = { 125 FIRE_ALARM = 1001, 126 FIRE_SUPERVISORY_ALARM = 1002, 127 BURGLAR_ALARM = 1003, 128 MEDICAL_ALARM = 1004, 129 POLICE_ALARM = 1005, 130 AUX1_ALARM = 1006, 131 AUX2_ALARM = 1007, 132 CARBON_MONOXIDE_ALARM = 1008, 133 EMERGENCY_ALARM = 1009, 134 FREEZE_ALARM = 1010, 135 GAS_ALARM = 1011, 136 HEAT_ALARM = 1012, 137 WATER_ALARM = 1013, 138 ANY_ALARM = 1014, 139 BURGLAR = 1015, 140 MEDICAL = 1023, 141 POLICE = 1031, 142 AUX1 = 1039, 143 AUX2 = 1047, 144 CO = 1055, 145 EMERGENCY = 1063, 146 FREEZE = 1071, 147 GAS = 1079, 148 HEAT = 1087, 149 WATER = 1095, 150 ANY = 1103 151 } 152 153 local TROUBLES = { 154 "AC Fail Trouble", 155 "Box Tamper Trouble", 156 "Fail To Communicate Trouble", 157 "EProm Memory Error Trouble", 158 "Low Battery Control Trouble", 159 "Transmitter Low Battery Trouble", 160 "Over Current Trouble", 161 "Telephone Fault Trouble", 162 "N/A", 163 "Output 2 Trouble", 164 "Missing Keypad Trouble", 165 "Zone Expander Trouble", 166 "Output Expander Trouble", 167 "N/A", 168 "ELKRP Remote Access Trouble", 169 "N/A", 170 "Common Area Not Armed Trouble", 171 "Flash Memory Error Trouble", 172 "Security Alert Trouble", 173 "Serial Port Expander Trouble", 174 "Lost Transmitter Trouble", 175 "GE Smoke CleanMe Trouble", 176 "Ethernet Trouble", 177 "N/A", 178 "N/A", 179 "N/A", 180 "N/A", 181 "N/A", 182 "N/A", 183 "N/A", 184 "N/A", 185 "Display Message In Keypad Line 1 Trouble", 186 "Display Message In Keypad Line 2 Trouble", 187 "Fire Trouble" 188 } 189 190 local ARMING_STATUSES = { 191 ['0'] = "Disarmed", 192 ['1'] = "Armed", 193 ['2'] = "Stay", 194 ['3'] = "StayInstant", 195 ['4'] = "Night", 196 ['5'] = "NightInstant", 197 ['6'] = "Vacation" 198 } 199 200 local ALARM_STATES = { 201 ['0'] = "None", 202 ['1'] = "Entrance Delay", 203 ['2'] = "Alarm Abort Delay", 204 ['3'] = "Fire Alarm", 205 ['4'] = "Medical Alarm", 206 ['5'] = "Police Alarm", 207 ['6'] = "Burglar Alarm", 208 ['7'] = "Aux1 Alarm", 209 ['8'] = "Aux2 Alarm", 210 -- ['9'] = "Aux3 Alarm", -- not used 211 -- [':'] = "Aux4 Alarm", -- not used 212 [';'] = "Carbon Monoxide Alarm", 213 ['<'] = "Emergency Alarm", 214 ['='] = "Freeze Alarm", 215 ['>'] = "Gas Alarm", 216 ['?'] = "Heat Alarm", 217 ['@'] = "Water Alarm", 218 ['A'] = "Fire Supervisory", 219 ['B'] = "Verify Fire" 220 } 221 222 local ZONE_STATUSES = { 223 ['0'] = "Normal", -- "Unconfigured" 224 ['1'] = "Normal", -- "Open" 225 ['2'] = "Normal", -- "EOL" 226 ['3'] = "Normal", -- "Short" 227 ['4'] = "N/A", 228 ['5'] = "Trouble", -- "Open" 229 ['6'] = "Trouble", -- "EOL" 230 ['7'] = "Trouble", -- "Short" 231 ['8'] = "N/A", 232 ['9'] = "Violated", -- "Open" 233 ['A'] = "Violated", -- "EOL" 234 ['B'] = "Violated", -- "Short" 235 ['C'] = "Bypassed", 236 ['D'] = "Bypassed", -- "Open" 237 ['E'] = "Bypassed", -- "EOL" 238 ['F'] = "Bypassed" -- "Short" 239 } 240 241 local LABEL_TYPES = { 242 ["00"] = "Zone Name", 243 ["01"] = "Area Name", 244 ["02"] = "User Name", 245 ["03"] = "Keypad Name", 246 ["04"] = "Output Name", 247 ["05"] = "Task Name", 248 ["06"] = "Telephone Name", 249 ["07"] = "Light Name", 250 ["08"] = "Alarm Duration Name", 251 ["09"] = "Custom Settings", 252 ["10"] = "Counters Names", 253 ["11"] = "Thermostat Names", 254 ["12"] = "Function Key 1 Name", 255 ["13"] = "Function Key 2 Name", 256 ["14"] = "Function Key 3 Name", 257 ["15"] = "Function Key 4 Name", 258 ["16"] = "Function Key 5 Name", 259 ["17"] = "Function Key 6 Name", 260 ["18"] = "Audio Zone Name", 261 ["19"] = "Audio Source Name" 262 } 239 263 240 264 local COMMAND_DESCRIPTIONS = { 265 ["a0"] = "Disarm", 266 ["a1"] = "Arm Away", 267 ["a2"] = "Arm Stay", 268 ["a3"] = "Arm Stay Instant", 269 ["a4"] = "Arm Night", 270 ["a5"] = "Arm Night Instant", 271 ["a6"] = "Arm Vacation", 241 272 ["as"] = "Request arming status", 242 273 ["kf"] = "Request chime modes", … … 253 284 254 285 286 local log = luup.log 287 255 288 local function debug (text) 256 289 if (DEBUG_MODE == true) then … … 262 295 local function task (text, mode) 263 296 debug (string.format ("(task) %s", text)) 264 if (mode == TASK _ERROR_PERM) then265 g_taskHandle = luup.task (text, TASK _ERROR, "ElkAlarmPanel", g_taskHandle)297 if (mode == TASK.ERROR_PERM) then 298 g_taskHandle = luup.task (text, TASK.ERROR, "ElkAlarmPanel", g_taskHandle) 266 299 else 267 300 g_taskHandle = luup.task (text, mode, "ElkAlarmPanel", g_taskHandle) 268 301 269 302 -- Clear the previous error, since they're all transient 270 if (mode ~= TASK _SUCCESS) then303 if (mode ~= TASK.SUCCESS) then 271 304 luup.call_delay ("clearTask", 30, "", false) 272 305 end … … 276 309 277 310 function clearTask() 278 task ("Clearing...", TASK_SUCCESS) 311 task ("Clearing...", TASK.SUCCESS) 312 return true 279 313 end 280 314 … … 323 357 324 358 359 local function setZoneState (zoneNo, variable, value) 360 local device = g_childDevices.zones[zoneNo].device 361 if (device) then 362 debug (string.format ("(setZoneState) zone %d (device %d), set %s='%s'", zoneNo, device, variable, tostring (value))) 363 luup.variable_set (SID.SECURITY, variable, value, device) 364 else 365 log (string.format ("(setZoneState) ERROR: No device for zone %d (variable=%s, value='%s').", zoneNo, variable, tostring (value))) 366 end 367 end 368 369 370 local function getPartitionState (partNo, variable) 371 local device = g_childDevices.partitions[partNo].device 372 if (device) then 373 local v = luup.variable_get (SID.PARTITION, variable, device) 374 debug (string.format ("(getPartitionState) partition %d (device %d), got '%s'", partNo, device, tostring (v))) 375 else 376 log (string.format ("(getPartitionState) ERROR: No device for partition %d (variable=%s).", partNo, variable)) 377 return nil 378 end 379 end 380 381 325 382 local function setPartitionState (partNo, variable, value) 326 if (g_childDevices.partitions[partNo].device ~= nil) then 327 luup.variable_set (PARTITION_SID, variable, value, g_childDevices.partitions[partNo].device) 383 local device = g_childDevices.partitions[partNo].device 384 if (device) then 385 debug (string.format ("(setPartitionState) partition %d (device %d), set %s='%s'", partNo, device, variable, tostring (value))) 386 luup.variable_set (SID.PARTITION, variable, value, device) 328 387 else 329 log (string.format ("(setPartitionState) ERROR: No n-existent partition #%d (variable = %s, value = %s).", partNo, variable, tostring (value)))388 log (string.format ("(setPartitionState) ERROR: No device for partition %d (variable=%s, value='%s').", partNo, variable, tostring (value))) 330 389 end 331 390 end … … 339 398 end 340 399 341 local length, msgType, data, checksum = msg:match ("^(%x%x)(%a%w)(.*)00(%x%x)$")400 local length, msgType, data, misc, checksum = msg:match ("^(%x%x)(%a%w)(.*)(%x%x)(%x%x)$") 342 401 if ((length == nil) or (msgType == nil) or (checksum == nil)) then 402 debug ("(checkMessage) Received message: " .. msg) 343 403 log ("(checkMessage) ERROR: The received message has invalid format.") 344 debug ("(checkMessage) Received message: " .. msg)345 task ("ERROR: The received message has invalid format.", TASK_ERROR)346 404 return nil 347 405 end 348 debug (string.format ("(checkMessage) length=%d(0x%s), message type=%s, data='%s', checksum=%s", tonumber (length, 16) or 0, length, msgType, tostring (data), checksum)) 406 407 debug (string.format ("(checkMessage) length=%d(0x%s), message type=%s, data='%s', misc=%s, checksum=%s", tonumber (length, 16) or 0, length, msgType, tostring (data), misc, checksum)) 408 409 -- There is a bug in the version 5.1.20: the reported length for EE, which is 0F is incorrect. 410 -- The correct length is 0E. This affects the checksum, so we bypass this message. 411 if (msgType == "EE") then 412 return "EE" 413 end 349 414 350 415 data = data or "" 351 416 352 local calculatedLength = #msgType + #data + 2+ #checksum417 local calculatedLength = #msgType + #data + #misc + #checksum 353 418 if (calculatedLength ~= tonumber (length, 16)) then 354 419 log ("(checkMessage) ERROR: The received message length is incorrect.") 355 task ("ERROR: The received message length is incorrect.", TASK_ERROR)356 420 return nil 357 421 end 358 422 359 local calculatedChecksum = calculateChecksum (length .. msgType .. data .. "00")423 local calculatedChecksum = calculateChecksum (length .. msgType .. data .. misc) 360 424 if (calculatedChecksum ~= tonumber (checksum, 16)) then 361 425 log ("(checkMessage) ERROR: The calculated checksum is incorrect.") 362 task ("ERROR: The calculated checksum is incorrect.", TASK_ERROR)363 426 return nil 364 427 end … … 429 492 430 493 local function processArmingStatusReport (data) 431 S = {} 432 U = {} 433 A = {} 494 S = {} -- Arming statuses 495 U = {} -- Arm up states 496 A = {} -- Alarm states 434 497 435 498 for i = 1, 8 do … … 443 506 end 444 507 445 for i in ipairs (g_childDevices.partitions) do508 for i in pairs (g_childDevices.partitions) do 446 509 g_childDevices.partitions[i].armingStatus = ARMING_STATUSES[S[i]] 447 g_childDevices.partitions[i].armUpState = ARM_UP_STATES[U[i]]510 g_childDevices.partitions[i].armUpState = U[i] 448 511 g_childDevices.partitions[i].alarmState = A[i] 449 if (A[i] and A[i] >= '3') then 450 451 local message = string.format ("ALARM: %s, partition #%d", ALARM_STATES[A[i]], i)512 513 if (A[i] >= '3') then -- We have an alarm. 514 local message = string.format ("ALARM: %s, %s", ALARM_STATES[A[i]], g_childDevices.partitions[i].label) 452 515 log (message) 453 task (message, TASK_ERROR_PERM) 516 task (message, TASK.ERROR_PERM) 517 518 setPartitionState (i, "Alarm", "Active") 519 setPartitionState (i, "AlarmMemory", "1") 520 setPartitionState (i, "LastAlarmActive", os.date()) 521 else 522 if (getPartitionState (i, "AlarmMemory") == "1") then -- There was an alarm, but it has been deactivated. 523 setPartitionState (i, "Alarm", "None") 524 setPartitionState (i, "AlarmMemory", "0") 525 clearTask() 526 end 527 end 528 end 529 530 for k, v in pairs (g_childDevices.partitions) do 531 local message = string.format ("armingStatus=%s, armUpState=%s, alarmState=%s", v.armingStatus, v.armUpState, v.alarmState) 532 debug ("(processArmingStatusReport) partition " .. tostring (k) .. ", " .. message) 533 if (not v.armingStatus) then 534 -- We don't have this partition's status. Consider it Disarmed and NotReady just to be safe. 535 setPartitionState (k, "ArmMode", "Disarmed") 536 setPartitionState (k, "DetailedArmMode", "NotReady") 537 elseif (v.armingStatus ~= "Disarmed") then 538 -- The partition is in one of the armed states. 539 setPartitionState (k, "ArmMode", "Armed") 540 setPartitionState (k, "DetailedArmMode", v.armingStatus) 541 else 542 -- The partition is disarmed. 543 setPartitionState (k, "ArmMode", "Disarmed") 544 if (v.armUpState == '0') then 545 setPartitionState (k, "DetailedArmMode", "NotReady") 546 elseif (v.armUpState <= '2') then 547 setPartitionState (k, "DetailedArmMode", "Ready") 548 else 549 log ("(processArmingStatusReport) Impossible combination of 'armingStatus' and 'armUpState'.") 550 end 454 551 end 455 552 end … … 464 561 local alarmZone = (tonumber (eventData) <= 208) and eventData or "N/A" 465 562 log (string.format ("ALARM: Alarm type = %s, area = %s, zone = %s", alarmType, tostring (alarmArea or "N/A"), alarmZone)) 466 setPartitionState (area, "Alarm", "Active") 467 setPartitionState (area, "AlarmMemory", "1") 468 setPartitionState (area, "LastAlarmActive", os.date()) 469 task (string.format ("ALARM: Alarm type = %s, area = %s, zone = %s", alarmType, tostring (alarmArea or "N/A"), alarmZone), TASK_ERROR_PERM) 563 564 task (string.format ("ALARM: Alarm type = %s, area = %s, zone = %s", alarmType, tostring (alarmArea or "N/A"), alarmZone), TASK.ERROR_PERM) 470 565 else 471 566 debug ("Unhandled event") … … 497 592 end 498 593 log (message) 499 task (message, TASK_ERROR_PERM) 594 task (message, TASK.ERROR_PERM) 595 end 596 end 597 end 598 599 600 local function processZoneChangeUpdate (data) 601 local zoneNo, status = data:match ("^(%d%d%d)(%x)$") 602 zoneNo = tonumber (zoneNo, 10) 603 debug (string.format ("(processZoneChangeUpdate) zone=%d, status=%s", zoneNo, ZONE_STATUSES[status])) 604 if (ZONE_STATUSES[status] == "Normal") then 605 luup.variable_set (SID.SECURITY, "Armed", "1", g_childDevices.zones[zoneNo].device) 606 luup.variable_set (SID.SECURITY, "Tripped", "0", g_childDevices.zones[zoneNo].device) 607 elseif (ZONE_STATUSES[status] == "Violated") then 608 luup.variable_set (SID.SECURITY, "Tripped", "1", g_childDevices.zones[zoneNo].device) 609 elseif (ZONE_STATUSES[status] == "Bypassed") then 610 luup.variable_set (SID.SECURITY, "Armed", "0", g_childDevices.zones[zoneNo].device) 611 else -- It's either in Trouble or in an invalid state. 612 luup.variable_set (SID.SECURITY, "Armed", "0", g_childDevices.zones[zoneNo].device) 613 luup.variable_set (SID.SECURITY, "Tripped", "0", g_childDevices.zones[zoneNo].device) 614 end 615 end 616 617 618 local function processZonePartitionReport (data) 619 for i in pairs (g_childDevices.zones) do 620 local c = data:sub (i, i) 621 if (c ~= '0') then 622 p = tonumber (c) 623 g_childDevices.zones[i].partition = p; 624 if (not g_childDevices.partitions[p]) then 625 g_childDevices.partitions[p] = {zones = {i}} 626 else 627 table.insert (g_childDevices.partitions[p].zones, i) 628 end 629 else 630 g_childDevices.zones[i].partition = 1; 500 631 end 501 632 end … … 504 635 505 636 local function processZoneStatusReport (data) 506 for i = 1, #data do 507 c = data:sub (i, i) 508 if (g_childDevices.zones[i]) then 509 if (ZONE_STATUSES[c][1] == "Trouble" or ZONE_STATUSES[c][1] == "Violated") then 510 luup.variable_set (SECURITY_SID, "Armed", "1", g_childDevices.zones[i].device) 511 luup.variable_set (SECURITY_SID, "Tripped", "1", g_childDevices.zones[i].device) 512 elseif (ZONE_STATUSES[c][1] == "Bypassed") then 513 luup.variable_set (SECURITY_SID, "Armed", "0", g_childDevices.zones[i].device) 514 luup.variable_set (SECURITY_SID, "Tripped", "0", g_childDevices.zones[i].device) 515 else -- By default, the sensors will be armed and untripped. 516 luup.variable_set (SECURITY_SID, "Armed", "1", g_childDevices.zones[i].device) 517 luup.variable_set (SECURITY_SID, "Tripped", "0", g_childDevices.zones[i].device) 518 end 519 end 520 end 521 end 522 523 524 local function processZonePartitionReport (data) 525 for i = 1, #data do 526 c = data:sub (i, i) 527 if (g_childDevices.zones[i]) then 528 if (c ~= '0') then 529 p = tonumber (c) 530 g_childDevices.zones[i].partition = p; 531 if (not g_childDevices.partitions[p]) then 532 g_childDevices.partitions[p] = {zones = {i}} 533 else 534 table.insert (g_childDevices.partitions[p].zones, i) 535 end 536 else 537 g_childDevices.zones[i].partition = "no partition"; 538 end 539 end 540 end 541 table.sort (g_childDevices.partitions) 637 for i in pairs (g_childDevices.zones) do 638 local c = data:sub (i, i) 639 debug (string.format ("(processZoneStatusReport) zone %d, status=%s", i, ZONE_STATUSES[c])) 640 if (ZONE_STATUSES[c] == "Normal") then 641 g_childDevices.zones[i].armed = "1" 642 g_childDevices.zones[i].tripped = "0" 643 elseif (ZONE_STATUSES[c] == "Violated") then 644 g_childDevices.zones[i].armed = "1" 645 g_childDevices.zones[i].tripped = "1" 646 elseif (ZONE_STATUSES[c] == "Bypassed") then 647 g_childDevices.zones[i].armed = "0" 648 g_childDevices.zones[i].tripped = "0" 649 else -- It's either in Trouble or in an invalid state. 650 g_childDevices.zones[i].armed = "0" 651 g_childDevices.zones[i].tripped = "0" 652 end 653 end 542 654 end 543 655 … … 571 683 debug ("(handlerFunc) Message type description: " .. self.description) 572 684 data = data:sub(4) -- We're interested only in the Chime information. 573 for i in ipairs (g_childDevices.partitions) do 574 g_childDevices.partitions[i].chimeMode = data[i] 685 for i in pairs (g_childDevices.partitions) do 686 local chimeEnabled = (data[i] == '0') and "0" or "1" 687 setPartitionState (i, "ChimeEnabled", chimeEnabled) 575 688 end 576 689 return true … … 615 728 local zone, status = data:match ("^(%d%d%d)(%d)$") 616 729 if (status == "1") then 617 return "bypassed" , zone730 return "bypassed" 618 731 end 619 return "unbypassed" , zone732 return "unbypassed" 620 733 end 621 734 }, … … 624 737 handlerFunc = function (self, data) 625 738 debug ("(handlerFunc) Message type description: " .. self.description) 626 processZone StatusReport(data)739 processZoneChangeUpdate (data) 627 740 return true 628 741 end … … 635 748 c = data:sub (i, i) 636 749 if (c ~= '0') then 637 g_childDevices.zones[i] = { definition = ZONE_DEFINITIONS[c]}750 g_childDevices.zones[i] = {} -- Create zone. 638 751 end 639 752 end … … 663 776 if (not msgType) then 664 777 msgType, data = checkMessage (data) 778 if (not msgType or tostring (msgType) == "") then 779 return false 780 end 665 781 end 666 782 … … 685 801 if (not msgType) then 686 802 log (string.format ("(%s) ERROR: %s", functionName, errorMsg)) 687 g_ errorMessage = errorMsg688 return false 689 end 690 691 local status = processMessage (data, msgType)692 803 g_status.errorMessage = errorMsg 804 return false 805 end 806 807 local status, data = processMessage (data, msgType) 808 693 809 if (msgType == expectedMsgType) then -- We received the expected message. 810 debug ("(readResponse) Got expected message.") 694 811 if (not status) then 695 812 log (string.format ("(%s) ERROR: %s", functionName, errorMsg)) 696 g_ errorMessage = errorMsg697 end 698 return status 813 g_status.errorMessage = errorMsg 814 end 815 return status, data 699 816 end 700 817 701 818 -- We received other message. Process it and read the next message. 702 819 local retryCount = 0 703 while (retryCount < MAX_RETRIES) do 820 while (retryCount <= MAX_RETRIES) do 821 luup.io.intercept() 704 822 debug ("(readResponse) Unexpected response type. Intercept next message.") 705 823 retryCount = retryCount + 1 … … 708 826 if (not msgType) then 709 827 log (string.format ("(%s) ERROR: %s", functionName, errorMsg)) 710 g_ errorMessage = errorMsg828 g_status.errorMessage = errorMsg 711 829 return false 712 830 end 713 831 714 status = processMessage (data, msgType)715 832 status, data = processMessage (data, msgType) 833 716 834 if (msgType == expectedMsgType) then -- We received the expected message. 835 debug ("(readResponse) Got expected message.") 717 836 if (not status) then 718 837 log (string.format ("(%s) ERROR: %s", functionName, errorMsg)) 719 g_ errorMessage = errorMsg838 g_status.errorMessage = errorMsg 720 839 end 721 return status 840 return status, data 722 841 end 723 842 end … … 725 844 -- Shouldn't get here. 726 845 return nil 846 end 847 848 849 local function readArmRequestResponse() 850 851 local readCnt = 0 852 853 while (readCnt <= MAX_READS) do 854 local msgType, data = checkMessage (luup.io.read()) 855 if (not msgType) then 856 return false 857 end 858 859 if (msgType == "AS") then 860 debug ("(readArmRequestResponse) Got expected message.") 861 return true 862 elseif (msgType == "IC") then -- Invalid PIN code. 863 debug ("(readArmRequestResponse) Got expected message.") 864 return "IC" 865 else 866 debug ("(readArmRequestResponse) Got unexpected message. Ignore it.") 867 readCnt = readCnt + 1 868 if (readCnt < MAX_READS) then 869 luup.io.intercept() 870 end 871 end 872 end 873 874 return false 875 end 876 877 878 local function readBypassRequestResponse() 879 880 local readCnt = 0 881 882 while (readCnt <= MAX_READS) do 883 local msgType, data = checkMessage (luup.io.read()) 884 if (not msgType) then 885 return false 886 end 887 888 if (msgType == "ZB") then 889 debug ("(readBypassRequestResponse) Got expected message.") 890 return processMessage (data, msgType) 891 elseif (msgType == "IC") then -- Invalid PIN code. 892 debug ("(readBypassRequestResponse) Got expected message.") 893 return "IC" 894 else 895 debug ("(readBypassRequestResponse) Got unexpected message. Process it and intercept the next one.") 896 readCnt = readCnt + 1 897 if (readCnt < MAX_READS) then 898 luup.io.intercept() 899 end 900 processMessage (data, msgType) 901 end 902 end 903 904 return false 727 905 end 728 906 … … 748 926 if (not sendCommand (msgType, data)) then 749 927 log (string.format ("(%s) ERROR: %s", functionName, errorMsg)) 750 g_ errorMessage = errorMsg928 g_status.errorMessage = errorMsg 751 929 return false 752 930 end … … 759 937 760 938 761 function storePinCode (pinCode) 762 debug ("(storePinCode) pinCode=" .. tostring (pinCode)) 939 function storePinCode (device, pinCode) 940 941 local partitionNo = extractPartition (luup.devices[device].id) 942 if (not partitionNo) then 943 log ("(storePinCode) ERROR: Found unexpected child.") 944 task ("Found unexpected child.", TASK.ERROR) 945 return false 946 end 763 947 764 948 if (not pinCode or pinCode == "") then 765 949 log ("(storePinCode) ERROR: Invalid PIN code.") 766 task (" ERROR: Invalid PIN code.", TASK_ERROR)950 task ("Invalid PIN code.", TASK.ERROR) 767 951 return false 768 952 end … … 771 955 if (not pinCode:match ("^%d%d%d%d%d%d$")) then 772 956 log ("(storePinCode) ERROR: Invalid PIN code.") 773 task ("ERROR: Invalid PIN code.", TASK_ERROR) 774 return false 775 end 776 777 g_pinCode = pinCode 957 task ("Invalid PIN code.", TASK.ERROR) 958 return false 959 end 960 961 g_pinCodes[tonumber (partitionNo)] = pinCode 962 debug ("(storePinCode) PIN code stored for partition " .. partitionNo .. ".") 963 return true 964 end 965 966 967 function clearPinCode (device) 968 local partitionNo = extractPartition (luup.devices[device].id) 969 if (not partitionNo) then 970 log ("(clearPinCode) ERROR: Found unexpected child.") 971 task ("Found unexpected child.", TASK.ERROR) 972 return false 973 end 974 975 g_pinCodes[tonumber (partitionNo)] = nil 976 debug ("(clearPinCode) PIN code cleared for partition " .. partitionNo .. ".") 977 return true 778 978 end 779 979 780 980 781 981 function requestArmMode (device, state, pinCode) 782 debug (string.format ("(requestArmMode) device=%d, state=%s, pinCode=%s", device, state, tostring (pinCode))) 783 784 if ((not pinCode or pinCode == "") and (not g_pinCode)) then 982 local functionName = "requestArmMode" 983 local errorMessage = "Failed to go into the requested arm mode." 984 985 debug (string.format ("(requestArmMode) device=%d, state=%s", device, state)) 986 987 local partitionNo = extractPartition (luup.devices[device].id) 988 if (not partitionNo) then 989 log ("(requestArmMode) ERROR: Found unexpected child.") 990 task ("Found unexpected child.", TASK.ERROR) 991 return false 992 end 993 994 partitionNo = tonumber (partitionNo) 995 996 pinCode = tonumber (pinCode) or g_pinCodes[partitionNo] 997 if (not pinCode) then 785 998 log ("(requestArmMode) ERROR: PIN code required.") 786 task ("ERROR: PIN code required.", TASK_ERROR) 787 return false 788 end 789 790 local partition = extractPartition (luup.devices[device].id) 791 if (not partition) then 792 log ("(requestArmMode) ERROR: Found unexpected child.") 793 task ("ERROR: Unknown error encountered.", TASK_ERROR) 999 task ("PIN code required.", TASK.ERROR) 794 1000 return false 795 1001 end … … 797 1003 -- All the arming commands are implicitly 'forced', 798 1004 -- so for the 'Force' request use 'Away' instead. 1005 state = (state == "Force") and "Armed" or state 1006 799 1007 local command 800 1008 if (state == "Disarmed") then 801 command = "a0" 1009 command = "a0" -- Disarm 802 1010 elseif ((state == "Armed") or (state == "Force")) then 803 command = "a1" 1011 command = "a1" -- Arm Away 804 1012 elseif (state == "Stay") then 805 command = "a2" 1013 command = "a2" -- Arm Stay 806 1014 elseif (state == "StayInstant") then 807 command = "a3" 1015 command = "a3" -- Arm Stay Instant 808 1016 elseif (state == "Night") then 809 command = "a4" 1017 command = "a4" -- Arm Night 810 1018 elseif (state == "NightInstant") then 811 command = "a5" 1019 command = "a5" -- Arm Night Instant 812 1020 elseif (state == "Vacation") then 813 command = "a6" 1021 command = "a6" -- Arm Vacation 814 1022 else 815 1023 log ("(requestArmMode) ERROR: Invalid state requested.") 816 task ("Invalid state requested.", TASK _ERROR)1024 task ("Invalid state requested.", TASK.ERROR) 817 1025 return false 818 1026 end … … 820 1028 local data 821 1029 if (pinCode and pinCode ~= "") then 822 data = partition .. padLeft (pinCode, 6, '0')1030 data = partitionNo .. padLeft (pinCode, 6, '0') 823 1031 else 824 data = partition .. g_pinCode825 end 826 827 local status = send Command (command, data)1032 data = partitionNo .. g_pinCodes 1033 end 1034 1035 local status = sendIntercepted (command, functionName, errorMessage, data) 828 1036 if (not status) then 829 log ("(requestArmMode) ERROR: Failed to send command.") 830 task ("Failed to send command.", TASK_ERROR) 831 return false 832 end 833 834 g_pinCode = pinCode 1037 task ("Failed to send command.", TASK.ERROR) 1038 return false 1039 end 1040 1041 local status = readArmRequestResponse() 1042 if (not status) then 1043 log ("(requestArmMode) ERROR: " .. errorMessage) 1044 task (errorMessage, TASK.ERROR) 1045 return false 1046 elseif (status == "IC") then 1047 log ("(requestArmMode) ERROR: Invalid PIN code.") 1048 task ("Invalid PIN code.", TASK.ERROR) 1049 return false 1050 end 1051 1052 g_pinCodes[partitionNo] = pinCode 1053 debug ("(requestArmMode) SUCCESS: Succesfully changed to the requested arm mode.") 1054 task ("SUCCESS: Arm mode succesfully changed.") 835 1055 return true 836 1056 end … … 839 1059 function requestQuickArmMode (device, state) 840 1060 log ("(requestQuickArmMode) Quick Arm not supported.") 841 task ("One Touch Arm/Disarm not supported.", TASK _ERROR)1061 task ("One Touch Arm/Disarm not supported.", TASK.ERROR) 842 1062 return false 843 1063 end … … 846 1066 function requestPanicMode (device, state) 847 1067 log ("(requestPanicMode) Panic Modes not supported.") 848 task ("Panic Modes not supported.", TASK _ERROR)1068 task ("Panic Modes not supported.", TASK.ERROR) 849 1069 return false 850 1070 end 851 1071 852 1072 853 local function unbypassZone (zoneNo, tryCount) 854 local functionName = "unbypassZone" 1073 local function unbypassZone (zoneNo, pinCode, tryCount) 855 1074 local errorMessage = string.format ("Failed to unbypass zone %d.", zoneNo) 856 1075 857 local status = sendIntercepted ("zb", functionName, errorMessage, string.format ("%s1%s", padLeft (zoneNo, 3, '0'), padLeft (g_pinCode, 6, '0'))) 1076 debug ("(unbypassZone) tryCount=" .. tostring (tryCount)) 1077 1078 local data = string.format ("%s%d%s", padLeft (zoneNo, 3, '0'), g_childDevices.zones[zoneNo].partition, padLeft (pinCode, 6, '0')) 1079 local status = sendIntercepted ("zb", "unbypassZone", errorMessage, data) 858 1080 if (not status) then 859 task ("ERROR: " .. errorMessage, TASK_ERROR) 860 return false 861 end 862 863 local status, zone = readResponse ({"ZB", "IC"}, functionName, errorMessage) 864 if (not status or zone ~= zoneNo) then 865 task ("ERROR: " .. errorMessage, TASK_ERROR) 866 return false 867 end 868 869 if (status == "unbypassed") then 870 debug (string.format ("(%s) SUCCESS: Unbypass successful.", functionName)) 1081 task (errorMessage, TASK.ERROR) 1082 return false 1083 end 1084 1085 local status = readBypassRequestResponse() 1086 debug ("(unbypassZone) status=" .. tostring (status)) 1087 if (not status) then 1088 log ("(unbypassZone) ERROR: " .. errorMessage) 1089 task (errorMessage, TASK.ERROR) 1090 return false 1091 elseif (status == "IC") then 1092 log ("(unbypassZone) ERROR: Invalid PIN code.") 1093 task ("Invalid PIN code.", TASK.ERROR) 1094 return false 1095 elseif (status == "unbypassed") then 1096 debug ("(unbypassZone) SUCCESS: Unbypass successful.") 871 1097 return true 872 1098 end … … 874 1100 tryCount = (tryCount or 0) + 1 875 1101 if (tryCount >= MAX_RETRIES) then 876 log ( string.format ("(%s) ERROR: %s", functionName, errorMessage))877 task ( "ERROR: " .. errorMessage, TASK_ERROR)878 return false 879 end 880 881 return unbypassZone (zoneNo, tryCount)882 end 883 884 885 local function bypassZone (zoneNo, tryCount) 886 local functionName = "bypassZone" 1102 log ("(unbypassZone) ERROR: " .. errorMessage) 1103 task (errorMessage, TASK.ERROR) 1104 return false 1105 end 1106 1107 debug ("(unbypassZone) Unbypass failed, trying again...") 1108 return unbypassZone (zoneNo, pinCode, tryCount) 1109 end 1110 1111 1112 local function bypassZone (zoneNo, pinCode, tryCount) 887 1113 local errorMessage = string.format ("Failed to bypass zone %d.", zoneNo) 888 1114 889 local status = sendIntercepted ("zb", functionName, errorMessage, string.format ("%s1%s", padLeft (zoneNo, 3, '0'), padLeft (g_pinCode, 6, '0'))) 1115 debug ("(bypassZone) tryCount=" .. tostring (tryCount)) 1116 1117 local data = string.format ("%s%d%s", padLeft (zoneNo, 3, '0'), g_childDevices.zones[zoneNo].partition, padLeft (pinCode, 6, '0')) 1118 local status = sendIntercepted ("zb", "bypassZone", errorMessage, data) 890 1119 if (not status) then 891 task ("ERROR: " .. errorMessage, TASK_ERROR) 892 return false 893 end 894 895 local status, zone = readResponse ({"ZB", "IC"}, functionName, errorMessage) 896 if (not status or zone ~= zoneNo) then 897 task ("ERROR: " .. errorMessage, TASK_ERROR) 898 return false 899 end 900 901 if (status == "bypassed") then 902 debug (string.format ("(%s) SUCCESS: Bypass successful.", functionName)) 1120 task (errorMessage, TASK.ERROR) 1121 return false 1122 end 1123 1124 local status = readBypassRequestResponse() 1125 debug ("(bypassZone) status=" .. tostring (status)) 1126 if (not status) then 1127 log ("(bypassZone) ERROR: " .. errorMessage) 1128 task (errorMessage, TASK.ERROR) 1129 return false 1130 elseif (status == "IC") then 1131 log ("(bypassZone) ERROR: Invalid PIN code.") 1132 task ("Invalid PIN code.", TASK.ERROR) 1133 return false 1134 elseif (status == "bypassed") then 1135 debug ("(bypassZone) SUCCESS: Bypass successful.") 903 1136 return true 904 1137 end … … 906 1139 tryCount = (tryCount or 0) + 1 907 1140 if (tryCount >= MAX_RETRIES) then 908 log (string.format ("(%s) ERROR: %s", functionName, errorMessage)) 909 task ("ERROR: " .. errorMessage, TASK_ERROR) 910 return false 911 end 912 913 return bypassZone (zoneNo, tryCount) 1141 log ("(bypassZone) ERROR: " .. errorMessage) 1142 task (errorMessage, TASK.ERROR) 1143 return false 1144 end 1145 1146 debug ("(bypassZone) Bypass failed, trying again...") 1147 return bypassZone (zoneNo, pinCode, tryCount) 914 1148 end 915 1149 916 1150 917 1151 function setArmed (device, newArmedValue) 918 debug (string.format ("(setArmed) device=%d, newArmedValue=%s, g_pinCode=%s", device, newArmedValue, tostring (g_pinCode))) 919 920 if (not g_pinCode) then 1152 debug (string.format ("(setArmed) device=%d, newArmedValue=%s", device, newArmedValue)) 1153 1154 local zoneNo = extractZone (luup.devices[device].id) 1155 if (not zoneNo) then 1156 log ("(setArmed) ERROR: Found unexpected child.") 1157 task ("Found unexpected child.", TASK.ERROR) 1158 return false 1159 end 1160 1161 zoneNo = tonumber (zoneNo) 1162 1163 local pinCode = g_pinCodes[g_childDevices.zones[zoneNo].partition] 1164 if (not pinCode) then 921 1165 log ("(setArmed) ERROR: Pin code required.") 922 task ("ERROR: Pin code required.", TASK_ERROR) 923 return false 924 end 925 926 local zone = extractZone (luup.devices[device].id) 927 if (not zone) then 928 log ("(setArmed) ERROR: Found unexpected child.") 929 task ("Unknown error encountered.", TASK_ERROR) 930 return false 931 end 932 933 local status; 1166 task ("Pin code required.", TASK.ERROR) 1167 return false 1168 end 1169 934 1170 if (newArmedValue == "0") then 935 status = bypassZone (zone)1171 return bypassZone (zoneNo, pinCode) 936 1172 else 937 status = unbypassZone (zone) 938 end 939 940 if (status) then 941 luup.variable_set (SECURITY_SID, "Armed", newArmedValue, device) 1173 return unbypassZone (zoneNo, pinCode) 942 1174 end 943 1175 end … … 947 1179 948 1180 1181 local function updateZoneStates (zoneNo) 1182 for k, v in pairs (g_childDevices.zones) do 1183 setZoneState (k, "Armed", v.armed) 1184 setZoneState (k, "Tripped", v.tripped) 1185 end 1186 end 1187 1188 1189 local function updatePartitionStates() 1190 for k, v in pairs (g_childDevices.partitions) do 1191 local armMode = (v.armingStatus == "Disarmed") and "Disarmed" or "Armed" 1192 1193 local detailedArmMode 1194 if (armMode == "Disarmed") then 1195 local boolExpr = (v.armUpState == '1') or (v.armUpState == '2') 1196 detailedArmMode = boolExpr and "Ready" or "NotReady" 1197 else 1198 detailedArmMode = v.armingStatus 1199 end 1200 1201 local alarm 1202 if (v.alarmState >= '0' and v.alarmState <= '2') then 1203 alarm = "None" 1204 elseif (v.alarmState >= '3') then 1205 alarm = "Active" 1206 end 1207 1208 local chimeEnabled = (v.chimeMode == '0') and "0" or "1" 1209 1210 setPartitionState (k, "ArmMode", armMode) 1211 setPartitionState (k, "DetailedArmMode", detailedArmMode) 1212 setPartitionState (k, "Alarm", alarm) 1213 setPartitionState (k, "ChimeEnabled", chimeEnabled) 1214 end 1215 end 1216 1217 949 1218 local function getChildDevices() 950 g_childDevices.partitions = {} 951 952 for k, v in ipairs (luup.devices) do 1219 for k, v in pairs (luup.devices) do 953 1220 if (v.device_num_parent == lug_device) then 954 debug (string.format ("(getChildDevices) Parsing luup.devices[%d]", k))955 1221 local zone = extractZone (v.id) 956 1222 if (zone ~= nil) then 1223 debug (string.format ("(getChildDevices) zone %s device=%d", zone, k)) 957 1224 g_childDevices.zones[tonumber (zone)].device = k 958 1225 else 959 1226 local partition = extractPartition (v.id) 960 1227 if (partition ~= nil) then 1228 debug (string.format ("(getChildDevices) partition %s device=%d", partition, k)) 961 1229 g_childDevices.partitions[tonumber (partition)].device = k 962 1230 else … … 971 1239 local function presetParameters (t) 972 1240 local params = {} 973 for _, param in ipairs (t) do 1241 for _, param in pairs (t) do 1242 debug (string.format ("(presetParameters) %s = %s", tostring (param[2]), tostring (param[3]))) 974 1243 table.insert (params, string.format ("%s,%s=%s", unpack (param))) 975 1244 end 976 1245 977 1246 return table.concat (params, "\n") 978 end979 980 981 local function getZoneParams (zoneNo)982 local armed983 if ((not g_childDevices.zones[zoneNo].status) or (g_childDevices.zones[zoneNo].status == "Bypassed")) then984 armed = "0"985 else986 armed = "1"987 end988 989 return presetParameters ({{SECURITY_SID, "Armed", armed}})990 1247 end 991 1248 … … 997 1254 998 1255 -- Door Sensors 999 doorSensors = luup.variable_get (PANEL_SID, "DoorSensors", lug_device) or "" 1000 for zn in doorSensors:gmatch ("%d+") do 1001 if (tonumber (zn, 10) == zoneNo) then 1002 return {type = "urn:schemas-micasaverde-com:device:DoorSensor:1", file = "D_DoorSensor1.xml"} 1256 local doorSensors = luup.variable_get (SID.PANEL, "DoorSensors", lug_device) or "" 1257 if (doorSensors == "") then 1258 luup.variable_set (SID.PANEL, "DoorSensors", doorSensors, lug_device) 1259 else 1260 for zn in doorSensors:gmatch ("%d+") do 1261 if (tonumber (zn, 10) == zoneNo) then 1262 return {type = "urn:schemas-micasaverde-com:device:DoorSensor:1", file = "D_DoorSensor1.xml"} 1263 end 1003 1264 end 1004 1265 end 1005 1266 1006 1267 -- Smoke Sensors 1007 smokeSensors = luup.variable_get (PANEL_SID, "SmokeSensors", lug_device) or "" 1008 for zn in smokeSensors:gmatch ("%d+") do 1009 if (tonumber (zn, 10) == zoneNo) then 1010 return {type = "urn:schemas-micasaverde-com:device:SmokeSensor:1", file = "D_SmokeSensor1.xml"} 1011 end 1012 end 1013 1014 -- Humidity Sensors 1015 humiditySensors = luup.variable_get (PANEL_SID, "HumiditySensors", lug_device) or "" 1016 for zn in humiditySensors:gmatch ("%d+") do 1017 if (tonumber (zn, 10) == zoneNo) then 1018 return {type = "urn:schemas-micasaverde-com:device:HumiditySensor:1", file = "D_HumiditySensor1.xml"} 1268 local smokeSensors = luup.variable_get (SID.PANEL, "SmokeSensors", lug_device) or "" 1269 if (smokeSensors == "") then 1270 luup.variable_set (SID.PANEL, "SmokeSensors", smokeSensors, lug_device) 1271 else 1272 for zn in smokeSensors:gmatch ("%d+") do 1273 if (tonumber (zn, 10) == zoneNo) then 1274 return {type = "urn:schemas-micasaverde-com:device:SmokeSensor:1", file = "D_SmokeSensor1.xml"} 1275 end 1019 1276 end 1020 1277 end … … 1025 1282 1026 1283 local function appendZones (rootPtr) 1027 for k, v in ipairs (g_childDevices.zones) do1284 for k, v in pairs (g_childDevices.zones) do 1028 1285 debug (string.format ("(appendZones) Appending zone %d", k)) 1029 1286 local device = getDeviceType (k) 1030 luup.chdev.append (lug_device, rootPtr, string.format ("elk_zone_%d", k), string.format ("Zone %d: %s", k, v.label), device.type, device.file, nil, getZoneParams (k), false)1287 luup.chdev.append (lug_device, rootPtr, string.format ("elk_zone_%d", k), string.format ("Zone %d: %s", k, v.label), device.type, device.file, nil, nil, false) 1031 1288 end 1032 1289 end … … 1050 1307 local errorMessage = "Failed to get zone names." 1051 1308 1052 for i in ipairs (g_childDevices.zones) do1309 for i in pairs (g_childDevices.zones) do 1053 1310 local status = sendIntercepted ("sd", functionName, errorMessage, string.format ("00%03d", i)) 1054 1311 if (status) then … … 1064 1321 1065 1322 1066 local function getPartitionParams (partNo)1067 local armMode = (g_childDevices.partitions[partNo].armingStatus == "Disarmed") and "Disarmed" or "Armed"1068 1069 local detailedArmMode1070 if (armMode == "Disarmed") then1071 detailedArmMode = (g_childDevices.partitions[partNo].armUpState == "Ready") and "Ready" or "NotReady"1072 end1073 1074 local alarm1075 if (g_childDevices.partitions[partNo].alarmState == '0') then1076 alarm = "None"1077 elseif (g_childDevices.partitions[partNo].alarmState >= '3') then1078 alarm = "Active"1079 end1080 1081 local chimeEnabled = (g_childDevices.partitions[partNo].chimeMode == '0') and "0" or "1"1082 1083 return presetParameters ({{PARTITION_SID, "ArmMode", armMode}, {PARTITION_SID, "DetailedArmMode", detailedArmMode}, {PARTITION_SID, "Alarm", alarm}, {PARTITION_SID, "ChimeEnabled", chimeEnabled}})1084 end1085 1086 1087 1323 local function appendPartitions (rootPtr) 1088 for k, v in ipairs (g_childDevices.partitions) do1324 for k, v in pairs (g_childDevices.partitions) do 1089 1325 debug (string.format ("(appendPartitions) Appending partition %d", k)) 1090 luup.chdev.append (lug_device, rootPtr, string.format ("elk_partition_%d", k), string.format ("Partition %d: %s", k, v.label), "urn:schemas-micasaverde-com:device:ElkAlarmPartition:1", "D_ElkAlarmPartition1.xml", nil, getPartitionParams (k), false)1326 luup.chdev.append (lug_device, rootPtr, string.format ("elk_partition_%d", k), string.format ("Partition %d: %s", k, v.label), "urn:schemas-micasaverde-com:device:ElkAlarmPartition:1", "D_ElkAlarmPartition1.xml", nil, nil, false) 1091 1327 end 1092 1328 end … … 1123 1359 local errorMessage = "Failed to get partition names." 1124 1360 1125 for i in ipairs (g_childDevices.partitions) do1361 for i in pairs (g_childDevices.partitions) do 1126 1362 local status = sendIntercepted ("sd", functionName, errorMessage, string.format ("01%03d", i)) 1127 1363 if (status) then … … 1180 1416 1181 1417 function start (lul_device) 1182 log ("Elk M1 Alarm Panel Plugin version " .. VERSION) 1418 log ("Elk M1 Panel Plugin version " .. VERSION .. " starting up...") 1419 1420 -- Mark the beginning of the startup process. 1421 g_status.startup = true 1422 1423 do 1424 local debugMode = luup.variable_get (SID.PANEL, "DebugMode", lul_device) 1425 if (debugMode == nil) then 1426 luup.variable_set (SID.PANEL, "DebugMode", "0", lul_device) 1427 debugMode = false 1428 end 1429 DEBUG_MODE = (debugMode == "1") and true or false 1430 end 1431 1432 lug_device = lul_device 1183 1433 1184 1434 local version = getVersion() or "N/A" 1185 1435 log ("M1 version " .. version) 1186 luup.variable_set (PANEL_SID, "FirmwareVersion", version, lul_device) 1187 1188 lug_device = lul_device 1436 luup.variable_set (SID.PANEL, "FirmwareVersion", version, lul_device) 1189 1437 1190 1438 local rootPtr = luup.chdev.start (lul_device) … … 1193 1441 local status = getZonesAndPartitions() 1194 1442 if (not status) then 1195 return false, g_ errorMessage, "Elk Alarm Panel"1443 return false, g_status.errorMessage, "Elk Alarm Panel" 1196 1444 end 1197 1445 1198 1446 getPartitionNames() 1447 1448 -- Create a device for each active partition. 1449 appendPartitions (rootPtr) 1450 1451 getZoneNames() 1452 1453 -- Create a device for each zone. 1454 appendZones (rootPtr) 1455 1456 luup.chdev.sync (lul_device, rootPtr) 1457 1458 -- Get a list with the created child devices. 1459 getChildDevices() 1199 1460 1200 1461 -- Get each Partition's status. 1201 1462 status = getPartitionStatuses() 1202 1463 if (not status) then 1203 return false, g_ errorMessage, "Elk Alarm Panel"1464 return false, g_status.errorMessage, "Elk Alarm Panel" 1204 1465 end 1205 1466 1206 1467 -- Get the Chime Mode for each partition. 1207 1468 getChimeModes() 1208 1209 -- Create a device for each active partition.1210 appendPartitions (rootPtr)1211 1212 getZoneNames()1213 1214 -- Create a device for each zone.1215 appendZones (rootPtr)1216 1217 luup.chdev.sync (lul_device, rootPtr)1218 1219 -- Get a list with the created child devices.1220 getChildDevices()1221 1469 1222 1470 -- Get each Zone's status. 1223 1471 status = getZoneStatuses() 1224 1472 if (not status) then 1225 return false, g_errorMessage, "Elk Alarm Panel" 1226 end 1227 1228 debug ("Elk Alarm Panel: Startup successful.") 1473 return false, g_status.errorMessage, "Elk Alarm Panel" 1474 end 1475 1476 -- Update the state variables for all partitions and zones. 1477 updatePartitionStates() 1478 updateZoneStates() 1479 1480 -- Mark the end of the startup process. 1481 g_status.startup = false 1482 1483 debug ("(Elk M1 Panel Plugin) SUCCESS: Startup successful.") 1229 1484 return true, "Startup successful.", "Elk Alarm Panel" 1230 1485 end -
/S_ElkAlarmPanel1.xml
r20 r30 7 7 <serviceStateTable> 8 8 <stateVariable> 9 <name>MotionSensors</name> 9 <name>DebugMode</name> 10 <datatype>boolean</datatype> 11 <setDefaultValue>1</setDefaultValue> 12 <defaultValue>0</defaultValue> 13 </stateVariable> 14 <stateVariable> 15 <name>FirmwareVersion</name> 10 16 <datatype>string</datatype> 11 17 </stateVariable> … … 22 28 <datatype>string</datatype> 23 29 </stateVariable> 24 <stateVariable>25 <name>FirmwareVersion</name>26 <datatype>string</datatype>27 </stateVariable>28 30 </serviceStateTable> 29 31 <actionList> … … 33 35 <argument> 34 36 <name>PinCode</name> 35 36 37 <direction>in</direction> 38 <relatedStateVariable>ui4</relatedStateVariable> 37 39 </argument> 38 40 </argumentList> 39 41 </action> 42 <action> 43 <name>ClearPinCode</name> 44 <argumentList></argumentList> 45 </action> 46 <action> 47 <name>ClearTask</name> 48 <argumentList></argumentList> 49 </action> 40 50 </actionList> 41 51 </scpd> -
/D_ElkAlarmPartition1.xml
r20 r30 15 15 <SCPDURL>S_AlarmPartition2.xml</SCPDURL> 16 16 </service> 17 <service> 18 <serviceType>urn:schemas-micasaverde-com:service:ElkAlarmPanel:1</serviceType> 19 <serviceId>urn:micasaverde-com:serviceId:ElkAlarmPanel1</serviceId> 20 <SCPDURL>S_ElkAlarmPanel1.xml</SCPDURL> 21 </service> 17 22 </serviceList> 18 23 </device> -
/D_ElkAlarmPartition1.json
r20 r30 1 1 { 2 "flashicon": "icons\/Door_Lock.swf", 3 "imgIconBody": "", 4 "imgIconDimmable": "", 5 "imgIconTurnable": "", 6 "imgIconMin": "pics\/devices\/Door_UNLOCKED.png", 7 "imgIconMax": "pics\/devices\/Door_LOCKED.png", 8 "halloIconsDir": "pics\/hallo", 9 "DisplayStatus": { 10 "Style": "label", 11 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 12 "Variable": "ArmMode", 13 "MinValue": "Disarmed", 14 "MaxValue": "Armed" 15 }, 16 "doc_url": { 17 "doc_language": 1, 18 "doc_manual": 1, 19 "doc_version": 1, 20 "doc_platform": 0, 21 "doc_page": "devices" 22 }, 23 "ToggleButton": 1, 24 "Tabs": [ 25 { 26 "Label": { 27 "lang_tag": "tabname_control", 28 "text": "Alarm Partition" 29 }, 30 "Position": "0", 31 "TabType": "flash", 32 "ControlGroup": [ 33 { 34 "id": "1" 35 }, 36 { 37 "id": "2" 38 } 39 ], 40 "Control": [ 41 { 42 "ControlGroup": "1", 43 "ControlHeader": "1", 44 "ControlType": "label", 45 "Label": { 46 "lang_tag": "device_settings_page", 47 "text": "Status" 48 }, 49 "Display": { 50 "Top": 0, 51 "Left": 50, 52 "Width": 200, 53 "Height": 20 54 } 55 }, 56 { 57 "ControlGroup": "1", 58 "ControlHeader": "1", 59 "ControlType": "variable", 60 "Display": { 61 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 62 "Variable": "DetailedArmMode", 63 "Top": 20, 64 "Left": 50, 65 "Width": 200, 66 "Height": 20 67 } 68 }, 69 { 70 "ControlType": "label", 71 "Label": { 72 "lang_tag": "device_settings_page", 73 "text": "One Touch Options" 74 }, 75 "Display": { 76 "Top": 60, 77 "Left": 50, 78 "Width": 200, 79 "Height": 20 80 } 81 }, 82 { 83 "ControlGroup": "1", 84 "ControlType": "button", 85 "Label": { 86 "lang_tag": "cmd_lock", 87 "text": "Arm" 88 }, 89 "Display": { 90 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 91 "Variable": "ArmMode", 92 "Value": "Armed", 93 "Top": 80, 94 "Left": 50, 95 "Width": 75, 96 "Height": 20 97 }, 98 "Command": { 99 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 100 "Action": "RequestQuickArmMode", 101 "Parameters": [ 102 { 103 "Name": "State", 104 "Value": "Armed" 105 } 106 ] 107 } 108 }, 109 { 110 "ControlGroup": "1", 111 "ControlType": "button", 112 "Label": { 113 "lang_tag": "cmd_lock", 114 "text": "Force" 115 }, 116 "Display": { 117 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 118 "Variable": "DetailedArmMode", 119 "Value": "Force", 120 "Top": 100, 121 "Left": 50, 122 "Width": 75, 123 "Height": 20 124 }, 125 "Command": { 126 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 127 "Action": "RequestQuickArmMode", 128 "Parameters": [ 129 { 130 "Name": "State", 131 "Value": "ArmedInstant" 132 } 133 ] 134 } 135 }, 136 { 137 "ControlGroup": "1", 138 "ControlType": "button", 139 "Label": { 140 "lang_tag": "cmd_lock", 141 "text": "Stay" 142 }, 143 "Display": { 144 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 145 "Variable": "DetailedArmMode", 146 "Value": "Stay", 147 "Top": 80, 148 "Left": 135, 149 "Width": 75, 150 "Height": 20 151 }, 152 "Command": { 153 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 154 "Action": "RequestQuickArmMode", 155 "Parameters": [ 156 { 157 "Name": "State", 158 "Value": "Stay" 159 } 160 ] 161 } 162 }, 163 { 164 "ControlGroup": "1", 165 "ControlType": "button", 166 "Label": { 167 "lang_tag": "cmd_lock", 168 "text": "iStay" 169 }, 170 "Display": { 171 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 172 "Variable": "DetailedArmMode", 173 "Value": "StayInstant", 174 "Top": 100, 175 "Left": 135, 176 "Width": 75, 177 "Height": 20 178 }, 179 "Command": { 180 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 181 "Action": "RequestQuickArmMode", 182 "Parameters": [ 183 { 184 "Name": "State", 185 "Value": "StayInstant" 186 } 187 ] 188 } 189 }, 190 { 191 "ControlGroup": "1", 192 "ControlType": "button", 193 "Label": { 194 "lang_tag": "cmd_lock", 195 "text": "Night" 196 }, 197 "Display": { 198 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 199 "Variable": "DetailedArmMode", 200 "Value": "Night", 201 "Top": 80, 202 "Left": 220, 203 "Width": 75, 204 "Height": 20 205 }, 206 "Command": { 207 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 208 "Action": "RequestQuickArmMode", 209 "Parameters": [ 210 { 211 "Name": "State", 212 "Value": "Night" 213 } 214 ] 215 } 216 }, 217 { 218 "ControlGroup": "1", 219 "ControlType": "button", 220 "Label": { 221 "lang_tag": "cmd_lock", 222 "text": "iNight" 223 }, 224 "Display": { 225 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 226 "Variable": "DetailedArmMode", 227 "Value": "NightInstant", 228 "Top": 100, 229 "Left": 220, 230 "Width": 75, 231 "Height": 20 232 }, 233 "Command": { 234 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 235 "Action": "RequestQuickArmMode", 236 "Parameters": [ 237 { 238 "Name": "State", 239 "Value": "NightInstant" 240 } 241 ] 242 } 243 }, 244 { 245 "ControlGroup": "2", 246 "ControlHeader": "1", 247 "ControlType": "label", 248 "Label": { 249 "lang_tag": "device_settings_page", 250 "text": "PIN Options" 251 }, 252 "Display": { 253 "Top": 140, 254 "Left": 50, 255 "Width": 200, 256 "Height": 20 257 } 258 }, 259 { 260 "ControlGroup": "2", 261 "ControlPair": "1", 262 "ControlType": "input", 263 "ID": "PINCode", 264 "Display": { 265 "Top": 160, 266 "Left": 50, 267 "Width": 100, 268 "Height": 20 269 } 270 }, 271 { 272 "ControlGroup": "2", 273 "ControlPair": "1", 274 "ControlType": "button", 275 "Label": { 276 "lang_tag": "cmd_set", 277 "text": "Arm" 278 }, 279 "Display": { 280 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 281 "Variable": "ArmMode", 282 "Value": "Armed", 283 "Top": 160, 284 "Left": 160, 285 "Width": 50, 286 "Height": 20 287 }, 288 "Command": { 289 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 290 "Action": "RequestArmMode", 291 "Parameters": [ 292 { 293 "Name": "State", 294 "Value": "Armed" 295 }, 296 { 297 "Name": "PINCode", 298 "ID": "PINCode" 299 } 300 ] 301 } 302 }, 303 { 304 "ControlGroup": "2", 305 "ControlPair": "1", 306 "ControlType": "button", 307 "Label": { 308 "lang_tag": "cmd_set", 309 "text": "Stay" 310 }, 311 "Display": { 312 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 313 "Variable": "DetailedArmMode", 314 "Value": "Stay", 315 "Top": 180, 316 "Left": 160, 317 "Width": 50, 318 "Height": 20 319 }, 320 "Command": { 321 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 322 "Action": "RequestArmMode", 323 "Parameters": [ 324 { 325 "Name": "State", 326 "Value": "Stay" 327 }, 328 { 329 "Name": "PINCode", 330 "ID": "PINCode" 331 } 332 ] 333 } 334 }, 335 { 336 "ControlGroup": "2", 337 "ControlPair": "1", 338 "ControlType": "button", 339 "Label": { 340 "lang_tag": "cmd_set", 341 "text": "Disarm" 342 }, 343 "Display": { 344 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 345 "Variable": "ArmMode", 346 "Value": "Disarmed", 347 "Top": 200, 348 "Left": 160, 349 "Width": 50, 350 "Height": 20 351 }, 352 "Command": { 353 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 354 "Action": "RequestArmMode", 355 "Parameters": [ 356 { 357 "Name": "State", 358 "Value": "Disarmed" 359 }, 360 { 361 "Name": "PINCode", 362 "ID": "PINCode" 363 } 364 ] 365 } 366 }, 367 { 368 "ControlType": "label", 369 "Label": { 370 "lang_tag": "device_settings_page", 371 "text": "Panic Alarm Options" 372 }, 373 "Display": { 374 "Top": 240, 375 "Left": 50, 376 "Width": 200, 377 "Height": 20 378 } 379 }, 380 { 381 "ControlType": "button", 382 "Label": { 383 "lang_tag": "cmd_set", 384 "text": "Police" 385 }, 386 "Display": { 387 "Top": 260, 388 "Left": 50, 389 "Width": 75, 390 "Height": 20 391 }, 392 "Command": { 393 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 394 "Action": "RequestPanicMode", 395 "Parameters": [ 396 { 397 "Name": "State", 398 "Value": "Police" 399 } 400 ] 401 } 402 }, 403 { 404 "ControlType": "button", 405 "Label": { 406 "lang_tag": "cmd_set", 407 "text": "Medical" 408 }, 409 "Display": { 410 "Top": 260, 411 "Left": 135, 412 "Width": 75, 413 "Height": 20 414 }, 415 "Command": { 416 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 417 "Action": "RequestPanicMode", 418 "Parameters": [ 419 { 420 "Name": "State", 421 "Value": "Medical" 422 } 423 ] 424 } 425 }, 426 { 427 "ControlType": "button", 428 "Label": { 429 "lang_tag": "cmd_set", 430 "text": "Fire" 431 }, 432 "Display": { 433 "Top": 260, 434 "Left": 220, 435 "Width": 75, 436 "Height": 20 437 }, 438 "Command": { 439 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 440 "Action": "RequestPanicMode", 441 "Parameters": [ 442 { 443 "Name": "State", 444 "Value": "Fire" 445 } 446 ] 447 } 448 }, 449 { 450 "ControlType": "label", 451 "Label": { 452 "lang_tag": "device_settings_page", 453 "text": "Vendor Options" 454 }, 455 "Display": { 456 "Top": 300, 457 "Left": 50, 458 "Width": 200, 459 "Height": 20 460 } 461 }, 462 { 463 "ControlType": "variable", 464 "Display": { 465 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 466 "Variable": "VendorStatus", 467 "Top": 320, 468 "Left": 50, 469 "Width": 200, 470 "Height": 20 471 } 472 }, 473 { 474 "ControlType": "variable", 475 "Display": { 476 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 477 "Variable": "VendorStatusCode", 478 "Top": 340, 479 "Left": 50, 480 "Width": 200, 481 "Height": 20 482 } 483 }, 484 { 485 "ControlType": "variable", 486 "Display": { 487 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 488 "Variable": "VendorStatusData", 489 "Top": 360, 490 "Left": 50, 491 "Width": 200, 492 "Height": 20 493 } 494 } 495 ] 496 }, 497 { 498 "Label": { 499 "lang_tag": "notifications", 500 "text": "Notifications" 501 }, 502 "Position": "2", 503 "TabType": "javascript", 504 "ScriptName": "shared.js", 505 "Function": "device_notifications" 506 }, 507 { 508 "Label": { 509 "lang_tag": "logs", 510 "text": "Logs" 511 }, 512 "Position": "3", 513 "TabType": "javascript", 514 "ScriptName": "shared.js", 515 "Function": "device_logs" 516 }, 517 { 518 "Label": { 519 "lang_tag": "advanced", 520 "text": "Advanced" 521 }, 522 "Position": "4", 523 "TabType": "javascript", 524 "ScriptName": "shared.js", 525 "Function": "advanced_device" 526 } 527 ], 528 "DeviceType": "urn:schemas-micasaverde-com:device:ElkAlarmPartition:1", 529 "eventList": { 530 "event_1": { 531 "label": "Armed state", 532 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 533 "argumentList" : { 534 "argument_1" : { 535 "dataType": "string", 536 "defaultValue": "Armed", 537 "allowedValueList" : { 538 "Yes" : "Armed", 539 "No" : "Disarmed" 540 }, 541 "name": "ArmMode", 542 "comparisson": "=", 543 "prefix": "Is Armed?", 544 "suffix": "" 545 } 546 } 547 }, 548 "event_2": { 549 "label": "Armed detailed state", 550 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 551 "argumentList" : { 552 "argument_1" : { 553 "dataType": "string", 554 "defaultValue": "Armed", 555 "allowedValueList" : { 556 "Disarmed" : "Disarmed", 557 "Armed" : "Armed", 558 "Stay" : "Stay", 559 "StayInstant" : "StayInstant", 560 "Night" : "Night", 561 "NightInstant" : "NightInstant", 562 "Force" : "Force", 563 "Ready" : "Ready", 564 "Vacation" : "Vacation", 565 "NotReady" : "NotReady", 566 "FailedToArm" : "FailedToArm", 567 "EntryDelay" : "EntryDelay", 568 "ExitDelay" : "ExitDelay" 569 }, 570 "name": "DetailedArmMode", 571 "comparisson": "=", 572 "prefix": "Armed state", 573 "suffix": "" 574 } 575 } 576 }, 577 "event_3": { 578 "label": "Alarm Active", 579 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 580 "argumentList" : { 581 "argument_1" : { 582 "dataType": "boolean", 583 "defaultValue": "Active", 584 "allowedValueList" : { 585 "Active" : "Active", 586 "NotActive" : "None" 587 }, 588 "name": "Alarm", 589 "comparisson": "=", 590 "prefix": "Is Active?", 591 "suffix": "" 592 } 593 } 594 }, 595 "event_4": { 596 "label": "A PIN Code is entered", 597 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 598 "argumentList" : { 599 "argument_1" : { 600 "dataType": "string", 601 "defaultValue": "", 602 "name": "LastUser", 603 "comparisson": "=", 604 "prefix": "User", 605 "suffix": "" 606 } 607 } 608 }, 609 "event_5": { 610 "label": "Vendor Status Code", 611 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 612 "argumentList" : { 613 "argument_1" : { 614 "dataType": "string", 615 "defaultValue": "", 616 "name": "VendorStatusCode", 617 "comparisson": "=", 618 "prefix": "Code", 619 "suffix": "" 620 } 621 } 622 } 623 }, 624 "sceneList": { 625 "group_1": { 626 "cmd_1": { 627 "label": "Set Partition ... (PIN)", 628 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 629 "action": "RequestArmMode", 630 "argumentList": { 631 "argument_1": { 632 "dataType": "string", 633 "defaultValue": "Disarmed", 634 "allowedValueList": { 635 "Disarmed" : "Disarmed", 636 "Armed" : "Armed", 637 "Stay" : "Stay", 638 "StayInstant" : "StayInstant", 639 "Night" : "Night", 640 "NightInstant" : "NightInstant", 641 "Force" : "Force", 642 "Vacation" : "Vacation" 643 }, 644 "name": "State", 645 "prefix": "State", 646 "suffix": "" 647 }, 648 "argument_2": { 649 "dataType": "ui4", 650 "defaultValue": "1234", 651 "allowedValueRange": { 652 "minimum": "0", 653 "maximum": "999999999999" 654 }, 655 "prefix" : "PIN", 656 "suffix" : "0-99999999, (insecure)", 657 "name": "PINCode" 658 } 659 } 660 } 661 }, 662 "group_2": { 663 "cmd_1": { 664 "label": "Set Partition Disarmed (No PIN)", 665 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 666 "action": "RequestQuickArmMode", 667 "arguments": { 668 "State": "Disarmed" 669 } 670 }, 671 "cmd_2": { 672 "label": "Set Partition Armed (No PIN)", 673 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 674 "action": "RequestQuickArmMode", 675 "arguments": { 676 "State": "Armed" 677 } 678 }, 679 "cmd_3": { 680 "label": "Set Partition Stay (No PIN)", 681 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 682 "action": "RequestQuickArmMode", 683 "arguments": { 684 "State": "Stay" 685 } 686 }, 687 "cmd_4": { 688 "label": "Set Partition StayInstant (No PIN)", 689 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 690 "action": "RequestQuickArmMode", 691 "arguments": { 692 "State": "StayInstant" 693 } 694 }, 695 "cmd_5": { 696 "label": "Set Partition Night (No PIN)", 697 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 698 "action": "RequestQuickArmMode", 699 "arguments": { 700 "State": "Night" 701 } 702 }, 703 "cmd_6": { 704 "label": "Set Partition NightInstant (No PIN)", 705 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 706 "action": "RequestQuickArmMode", 707 "arguments": { 708 "State": "NightInstant" 709 } 710 }, 711 "cmd_7": { 712 "label": "Set Partition Force (No PIN)", 713 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 714 "action": "RequestQuickArmMode", 715 "arguments": { 716 "State": "Force" 717 } 718 }, 719 "cmd_8": { 720 "label": "Set Partition Vacation (No PIN)", 721 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 722 "action": "RequestQuickArmMode", 723 "arguments": { 724 "State": "Vacation" 725 } 726 } 727 }, 728 "group_3": { 729 "cmd_1": { 730 "label": "Request Medical Panic", 731 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 732 "action": "RequestPanicMode", 733 "arguments": { 734 "State": "Medical" 735 } 736 }, 737 "cmd_2": { 738 "label": "Request Police Panic", 739 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 740 "action": "RequestPanicMode", 741 "arguments": { 742 "State": "Police" 743 } 744 }, 745 "cmd_3": { 746 "label": "Request Fire Panic", 747 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 748 "action": "RequestPanicMode", 749 "arguments": { 750 "State": "Fire" 751 } 752 } 753 } 754 } 2 "flashicon": "icons\/Door_Lock.swf", 3 "imgIconBody": "", 4 "imgIconDimmable": "", 5 "imgIconTurnable": "", 6 "imgIconMin": "pics\/devices\/Door_UNLOCKED.png", 7 "imgIconMax": "pics\/devices\/Door_LOCKED.png", 8 "halloIconsDir": "pics\/hallo", 9 "DisplayStatus": { 10 "Style": "label", 11 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 12 "Variable": "ArmMode", 13 "MinValue": "Disarmed", 14 "MaxValue": "Armed" 15 }, 16 "doc_url": { 17 "doc_language": 1, 18 "doc_manual": 1, 19 "doc_version": 1, 20 "doc_platform": 0, 21 "doc_page": "devices" 22 }, 23 "ToggleButton": 1, 24 "Tabs": [ 25 { 26 "Label": { 27 "lang_tag": "tab_alarm_partition", 28 "text": "Alarm Partition" 29 }, 30 "Position": "0", 31 "TabType": "flash", 32 "ControlGroup": [ 33 { 34 "id": "1", 35 "type": "info" 36 } 37 ], 38 "Control": [ 39 { 40 "ControlGroup": "1", 41 "ControlHeader": "1", 42 "ControlType": "label", 43 "Label": { 44 "lang_tag": "label_status", 45 "text": "Status:" 46 }, 47 "Display": { 48 "Top": 20, 49 "Left": 285, 50 "Width": 75, 51 "Height": 20 52 } 53 }, 54 { 55 "ControlGroup": "1", 56 "ControlHeader": "1", 57 "ControlType": "variable", 58 "Display": { 59 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 60 "Variable": "DetailedArmMode", 61 "Top": 40, 62 "Left": 285, 63 "Width": 75, 64 "Height": 20 65 } 66 }, 67 { 68 "ControlType": "label", 69 "Label": { 70 "lang_tag": "device_settings_page", 71 "text": "PIN Code:" 72 }, 73 "Display": { 74 "Top": 80, 75 "Left": 70, 76 "Width": 75, 77 "Height": 20 78 } 79 }, 80 { 81 "ControlType": "input", 82 "ID": "PINCode", 83 "Display": { 84 "Top": 105, 85 "Left": 70, 86 "Width": 75, 87 "Height": 20 88 } 89 }, 90 { 91 "ControlType": "button", 92 "Label": { 93 "lang_tag": "button_store", 94 "text": "Store" 95 }, 96 "Display": { 97 "Top": 130, 98 "Left": 70, 99 "Width": 75, 100 "Height": 20 101 }, 102 "Command": { 103 "Service": "urn:micasaverde-com:serviceId:ElkAlarmPanel1", 104 "Action": "StorePinCode", 105 "Parameters": [ 106 { 107 "Name": "PinCode", 108 "ID": "PINCode" 109 } 110 ] 111 } 112 }, 113 { 114 "ControlType": "button", 115 "Label": { 116 "lang_tag": "button_clear", 117 "text": "Clear" 118 }, 119 "Display": { 120 "Top": 150, 121 "Left": 70, 122 "Width": 75, 123 "Height": 20 124 }, 125 "Command": { 126 "Service": "urn:micasaverde-com:serviceId:ElkAlarmPanel1", 127 "Action": "ClearPinCode", 128 "Parameters": [] 129 } 130 }, 131 { 132 "ControlType": "label", 133 "Label": { 134 "lang_tag": "label_arm_mode", 135 "text": "Arm Mode:" 136 }, 137 "Display": { 138 "Top": 80, 139 "Left": 285, 140 "Width": 75, 141 "Height": 20 142 } 143 }, 144 { 145 "ControlType": "button", 146 "Label": { 147 "lang_tag": "button_away", 148 "text": "Away" 149 }, 150 "Display": { 151 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 152 "Variable": "DetailedArmMode", 153 "Value": "Armed", 154 "Top": 100, 155 "Left": 200, 156 "Width": 75, 157 "Height": 20 158 }, 159 "Command": { 160 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 161 "Action": "RequestArmMode", 162 "Parameters": [ 163 { 164 "Name": "State", 165 "Value": "Armed" 166 }, 167 { 168 "Name": "PINCode", 169 "ID": "PINCode" 170 } 171 ] 172 } 173 }, 174 { 175 "ControlType": "button", 176 "Label": { 177 "lang_tag": "button_vacation", 178 "text": "Vacation" 179 }, 180 "Display": { 181 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 182 "Variable": "DetailedArmMode", 183 "Value": "Vacation", 184 "Top": 120, 185 "Left": 200, 186 "Width": 75, 187 "Height": 20 188 }, 189 "Command": { 190 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 191 "Action": "RequestArmMode", 192 "Parameters": [ 193 { 194 "Name": "State", 195 "Value": "Vacation" 196 }, 197 { 198 "Name": "PINCode", 199 "ID": "PINCode" 200 } 201 ] 202 } 203 }, 204 { 205 "ControlType": "button", 206 "Label": { 207 "lang_tag": "button_stay", 208 "text": "Stay" 209 }, 210 "Display": { 211 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 212 "Variable": "DetailedArmMode", 213 "Value": "Stay", 214 "Top": 100, 215 "Left": 285, 216 "Width": 75, 217 "Height": 20 218 }, 219 "Command": { 220 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 221 "Action": "RequestArmMode", 222 "Parameters": [ 223 { 224 "Name": "State", 225 "Value": "Stay" 226 }, 227 { 228 "Name": "PINCode", 229 "ID": "PINCode" 230 } 231 ] 232 } 233 }, 234 { 235 "ControlType": "button", 236 "Label": { 237 "lang_tag": "button_istay", 238 "text": "iStay" 239 }, 240 "Display": { 241 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 242 "Variable": "DetailedArmMode", 243 "Value": "StayInstant", 244 "Top": 120, 245 "Left": 285, 246 "Width": 75, 247 "Height": 20 248 }, 249 "Command": { 250 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 251 "Action": "RequestArmMode", 252 "Parameters": [ 253 { 254 "Name": "State", 255 "Value": "StayInstant" 256 }, 257 { 258 "Name": "PINCode", 259 "ID": "PINCode" 260 } 261 ] 262 } 263 }, 264 { 265 "ControlType": "button", 266 "Label": { 267 "lang_tag": "button_night", 268 "text": "Night" 269 }, 270 "Display": { 271 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 272 "Variable": "DetailedArmMode", 273 "Value": "Night", 274 "Top": 100, 275 "Left": 370, 276 "Width": 75, 277 "Height": 20 278 }, 279 "Command": { 280 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 281 "Action": "RequestArmMode", 282 "Parameters": [ 283 { 284 "Name": "State", 285 "Value": "Night" 286 }, 287 { 288 "Name": "PINCode", 289 "ID": "PINCode" 290 } 291 ] 292 } 293 }, 294 { 295 "ControlType": "button", 296 "Label": { 297 "lang_tag": "button_inight", 298 "text": "iNight" 299 }, 300 "Display": { 301 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 302 "Variable": "DetailedArmMode", 303 "Value": "NightInstant", 304 "Top": 120, 305 "Left": 370, 306 "Width": 75, 307 "Height": 20 308 }, 309 "Command": { 310 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 311 "Action": "RequestArmMode", 312 "Parameters": [ 313 { 314 "Name": "State", 315 "Value": "NightInstant" 316 }, 317 { 318 "Name": "PINCode", 319 "ID": "PINCode" 320 } 321 ] 322 } 323 }, 324 { 325 "ControlType": "button", 326 "Label": { 327 "lang_tag": "button_disarm", 328 "text": "Disarm" 329 }, 330 "Display": { 331 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 332 "Variable": "ArmMode", 333 "Value": "Disarmed", 334 "Top": 140, 335 "Left": 285, 336 "Width": 75, 337 "Height": 20 338 }, 339 "Command": { 340 "Service": "urn:micasaverde-com:serviceId:AlarmPartition2", 341 "Action": "RequestArmMode", 342 "Parameters": [ 343 { 344 "Name": "State", 345 "Value": "Disarmed" 346 }, 347 { 348 "Name": "PINCode", 349 "ID": "PINCode" 350 } 351 ] 352 } 353 } 354 ] 355 }, 356 { 357 "Label": { 358 "lang_tag": "notifications", 359 "text": "Notifications" 360 }, 361 "Position": "2", 362 "TabType": "javascript", 363 "ScriptName": "shared.js", 364 "Function": "device_notifications" 365 }, 366 { 367 "Label": { 368 "lang_tag": "logs", 369 "text": "Logs" 370 }, 371 "Position": "3", 372 "TabType": "javascript", 373 "ScriptName": "shared.js", 374 "Function": "device_logs" 375 }, 376 { 377 "Label": { 378 "lang_tag": "advanced", 379 "text": "Advanced" 380 }, 381 "Position": "4", 382 "TabType": "javascript", 383 "ScriptName": "shared.js", 384 "Function": "advanced_device" 385 } 386 ], 387 "DeviceType": "urn:schemas-micasaverde-com:device:ElkAlarmPartition:1", 388 "eventList": { 389 "event_1": { 390 "label": "Armed state", 391 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 392 "argumentList" : { 393 "argument_1" : { 394 "dataType": "string", 395 "defaultValue": "Armed", 396 "allowedValueList" : { 397 "Yes" : "Armed", 398 "No" : "Disarmed" 399 }, 400 "name": "ArmMode", 401 "comparisson": "=", 402 "prefix": "Is Armed?", 403 "suffix": "" 404 } 405 } 406 }, 407 "event_2": { 408 "label": "Armed detailed state", 409 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 410 "argumentList" : { 411 "argument_1" : { 412 "dataType": "string", 413 "defaultValue": "Armed", 414 "allowedValueList" : { 415 "Disarmed" : "Disarmed", 416 "Armed" : "Armed", 417 "Stay" : "Stay", 418 "StayInstant" : "StayInstant", 419 "Night" : "Night", 420 "NightInstant" : "NightInstant", 421 "Force" : "Force", 422 "Ready" : "Ready", 423 "Vacation" : "Vacation", 424 "NotReady" : "NotReady", 425 "FailedToArm" : "FailedToArm", 426 "EntryDelay" : "EntryDelay", 427 "ExitDelay" : "ExitDelay" 428 }, 429 "name": "DetailedArmMode", 430 "comparisson": "=", 431 "prefix": "Armed state", 432 "suffix": "" 433 } 434 } 435 }, 436 "event_3": { 437 "label": "Alarm Active", 438 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 439 "argumentList" : { 440 "argument_1" : { 441 "dataType": "boolean", 442 "defaultValue": "Active", 443 "allowedValueList" : { 444 "Active" : "Active", 445 "NotActive" : "None" 446 }, 447 "name": "Alarm", 448 "comparisson": "=", 449 "prefix": "Is Active?", 450 "suffix": "" 451 } 452 } 453 }, 454 "event_4": { 455 "label": "A PIN Code is entered", 456 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 457 "argumentList" : { 458 "argument_1" : { 459 "dataType": "string", 460 "defaultValue": "", 461 "name": "LastUser", 462 "comparisson": "=", 463 "prefix": "User", 464 "suffix": "" 465 } 466 } 467 }, 468 "event_5": { 469 "label": "Vendor Status Code", 470 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 471 "argumentList" : { 472 "argument_1" : { 473 "dataType": "string", 474 "defaultValue": "", 475 "name": "VendorStatusCode", 476 "comparisson": "=", 477 "prefix": "Code", 478 "suffix": "" 479 } 480 } 481 } 482 }, 483 "sceneList": { 484 "group_1": { 485 "cmd_1": { 486 "label": "Set Partition ... (PIN)", 487 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 488 "action": "RequestArmMode", 489 "argumentList": { 490 "argument_1": { 491 "dataType": "string", 492 "defaultValue": "Disarmed", 493 "allowedValueList": { 494 "Disarmed" : "Disarmed", 495 "Armed" : "Armed", 496 "Stay" : "Stay", 497 "StayInstant" : "StayInstant", 498 "Night" : "Night", 499 "NightInstant" : "NightInstant", 500 "Force" : "Force", 501 "Vacation" : "Vacation" 502 }, 503 "name": "State", 504 "prefix": "State", 505 "suffix": "" 506 }, 507 "argument_2": { 508 "dataType": "ui4", 509 "defaultValue": "1234", 510 "allowedValueRange": { 511 "minimum": "0", 512 "maximum": "999999999999" 513 }, 514 "prefix" : "PIN", 515 "suffix" : "0-99999999, (insecure)", 516 "name": "PINCode" 517 } 518 } 519 } 520 }, 521 "group_2": { 522 "cmd_1": { 523 "label": "Set Partition Disarmed (No PIN)", 524 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 525 "action": "RequestArmMode", 526 "arguments": { 527 "State": "Disarmed" 528 } 529 }, 530 "cmd_2": { 531 "label": "Set Partition Armed (No PIN)", 532 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 533 "action": "RequestArmMode", 534 "arguments": { 535 "State": "Armed" 536 } 537 }, 538 "cmd_3": { 539 "label": "Set Partition Stay (No PIN)", 540 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 541 "action": "RequestArmMode", 542 "arguments": { 543 "State": "Stay" 544 } 545 }, 546 "cmd_4": { 547 "label": "Set Partition StayInstant (No PIN)", 548 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 549 "action": "RequestArmMode", 550 "arguments": { 551 "State": "StayInstant" 552 } 553 }, 554 "cmd_5": { 555 "label": "Set Partition Night (No PIN)", 556 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 557 "action": "RequestArmMode", 558 "arguments": { 559 "State": "Night" 560 } 561 }, 562 "cmd_6": { 563 "label": "Set Partition NightInstant (No PIN)", 564 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 565 "action": "RequestArmMode", 566 "arguments": { 567 "State": "NightInstant" 568 } 569 }, 570 "cmd_7": { 571 "label": "Set Partition Force (No PIN)", 572 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 573 "action": "RequestArmMode", 574 "arguments": { 575 "State": "Force" 576 } 577 }, 578 "cmd_8": { 579 "label": "Set Partition Vacation (No PIN)", 580 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 581 "action": "RequestArmMode", 582 "arguments": { 583 "State": "Vacation" 584 } 585 } 586 }, 587 "group_3": { 588 "cmd_1": { 589 "label": "Request Medical Panic", 590 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 591 "action": "RequestPanicMode", 592 "arguments": { 593 "State": "Medical" 594 } 595 }, 596 "cmd_2": { 597 "label": "Request Police Panic", 598 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 599 "action": "RequestPanicMode", 600 "arguments": { 601 "State": "Police" 602 } 603 }, 604 "cmd_3": { 605 "label": "Request Fire Panic", 606 "serviceId": "urn:micasaverde-com:serviceId:AlarmPartition2", 607 "action": "RequestPanicMode", 608 "arguments": { 609 "State": "Fire" 610 } 611 } 612 } 613 } 755 614 } -
/I_ElkAlarmPanel1.xml
r20 r30 56 56 <name>StorePinCode</name> 57 57 <run> 58 elkPlugin.storePinCode (lul_settings.PinCode) 58 elkPlugin.storePinCode (lul_device, lul_settings.PinCode) 59 </run> 60 </action> 61 <action> 62 <serviceId>urn:micasaverde-com:serviceId:ElkAlarmPanel1</serviceId> 63 <name>ClearPinCode</name> 64 <run> 65 elkPlugin.clearPinCode (lul_device) 66 </run> 67 </action> 68 <action> 69 <serviceId>urn:micasaverde-com:serviceId:ElkAlarmPanel1</serviceId> 70 <name>ClearTask</name> 71 <run> 72 elkPlugin.clearTask() 59 73 </run> 60 74 </action>
Note: See TracChangeset
for help on using the changeset viewer.