Changeset 41
- Timestamp:
- 2012-12-02 23:19:32 (12 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/D_Powermax.json ¶
r39 r41 61 61 "Display": { 62 62 "Service": "urn:micasaverde-com:serviceId:PowermaxAlarmPanel1", 63 "Variable": "P owermaxVersion",63 "Variable": "PluginVersion", 64 64 "Top": 25, 65 65 "Left": 150, -
TabularUnified trunk/L_Powermax.lua ¶
r40 r41 8 8 local bitw = require("bit") 9 9 10 local POWERMAX_VERSION = "1.0 alpha" 11 local LOG_DEBUG = true 10 local PLUGIN_VERSION = "1.0 alpha" 12 11 local MotionOffDelay = 5 13 12 … … 36 35 end 37 36 37 -- DEVICES -- 38 local pmPanelDev = 0 39 local pmPartitionDev_t = { 0, 0, 0 } 40 local pmPanelTypeNr = 3 -- assume Powerlink Pro (no partitions) by default 38 41 -- MESSAGE HANDLING -- 39 42 local pmIncomingPdu = "" … … 47 50 local TIMEOUT = 20 -- wait max. 20 sec for a response 48 51 local MSG_RETRIES = 10 49 -- DEVICES --50 local panel_device = 051 local partition_device = 052 52 -- SETTINGS -- 53 local pmSettings_t = { [0x00] = "", [0x01] = "", [0x02] = "", [0x04] = "", [0x09] = "", [0x0A] = "", [0x0B] = ""}53 local pmSettings_t = {} 54 54 local pmForcedDisarmCode = string.char(0x00, 0x00) 55 55 local pmPincode_t = { string.char(0x00, 0x00) } 56 local pm PanelSerial = ""56 local pmLang = "EN" 57 57 -- EVENT LOG -- 58 58 local pmEventLog = "" … … 64 64 local pmPowerlinkRetry = 0 65 65 local PL_RETRIES = 3 66 --- Debugging --- 67 local pmLogDebug = true 68 local pmFilenameLog = "/var/log/cmh/powermax_pdu.txt" 69 local pmFilenameSettings = "/var/log/cmh/powermax_settings.txt" 66 70 67 71 local PANEL_SID = "urn:micasaverde-com:serviceId:PowermaxAlarmPanel1" … … 69 73 local SECURITY_SID = "urn:micasaverde-com:serviceId:SecuritySensor1" 70 74 local SENSOR_SID = "urn:micasaverde-com:serviceId:HaDevice1" 75 local KEYPAD_SID = "urn:micasaverde-com:serviceId:Keypad1" 71 76 72 77 local X10DEVICE_SID = "urn:upnp-org:serviceId:SwitchPower1" … … 78 83 local CON_SENSOR_INIT = SECURITY_SID .. ",Tripped=0" 79 84 local CON_BATSENSOR_INIT = CON_SENSOR_INIT .. "\n" .. SENSOR_SID .. ",BatteryLevel=100" 85 local CON_SIREN = X10DEVICE_SID .. ",Target=0\n" .. X10DEVICE_SID .. ",Status=0\n" 86 local CON_KEYPAD = KEYPAD_SID .. ",Status=0" 80 87 81 88 local pmDevices_t = { 82 VAR_ALARM = { "urn:schemas-micasaverde-com:device:AlarmPartition:2", "D_PowermaxPartition2.xml", "", "", true }, 83 VAR_SWITCH = { "urn:schemas-micasaverde-com:device:BinaryLight:1", "D_BinaryLight1.xml", "", CON_X10SW_INIT, false }, 84 VAR_DIM = { "urn:schemas-micasaverde-com:device:DimmableLight:1", "D_DimmableLight1.xml", "",CON_X10DIM_INIT, false }, 85 VAR_DOOR = { "urn:schemas-micasaverde-com:device:DoorSensor:1", "D_DoorSensor1.xml", "", CON_BATSENSOR_INIT, false }, 86 VAR_MOTION = { "urn:schemas-micasaverde-com:device:MotionSensor:1", "D_MotionSensor1.xml", "", CON_BATSENSOR_INIT, false }, 87 VAR_SMOKE = { "urn:schemas-micasaverde-com:device:SmokeSensor:1", "D_SmokeSensor1.xml", "", CON_BATSENSOR_INIT, false } 89 VAR_PARTITION = { "urn:schemas-micasaverde-com:device:AlarmPartition:2", "D_PowermaxPartition2.xml", "", "", true }, 90 VAR_SWITCH = { "urn:schemas-micasaverde-com:device:BinaryLight:1", "D_BinaryLight1.xml", "", CON_X10SW_INIT, false }, 91 VAR_DIM = { "urn:schemas-micasaverde-com:device:DimmableLight:1", "D_DimmableLight1.xml", "",CON_X10DIM_INIT, false }, 92 VAR_MAGNET = { "urn:schemas-micasaverde-com:device:DoorSensor:1", "D_DoorSensor1.xml", "", CON_BATSENSOR_INIT, false }, 93 VAR_MOTION = { "urn:schemas-micasaverde-com:device:MotionSensor:1", "D_MotionSensor1.xml", "", CON_BATSENSOR_INIT, false }, 94 VAR_SMOKE = { "urn:schemas-micasaverde-com:device:SmokeSensor:1", "D_SmokeSensor1.xml", "", CON_BATSENSOR_INIT, false }, 95 VAR_SIREN = { "urn:schemas-micasaverde-com:device:Siren:1", "D_Siren1.xml", "", CON_SIREN, false }, 96 VAR_KEYPAD = { "urn:schemas-micasaverde-com:service:Keypad:1", "D_Keypad1.xml", "", CON_KEYPAD, false } 88 97 } 89 98 … … 93 102 local pmSendMsg_t = { 94 103 MSG_INIT = { string.char(0xAB, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43), nil }, 95 MSG_RESTORE = { string.char(0xAB, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43), nil},104 MSG_RESTORE = { string.char(0xAB, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43), 0xA5 }, 96 105 MSG_ENROLL = { string.char(0xAB, 0x0A, 0x00, 0x00) .. pmDownloadCode .. string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x43), nil }, 97 106 MSG_EVENTLOG = { string.char(0xA0, 0x00, 0x00, 0x00) .. "pin" .. string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x43), 0xA0 }, … … 102 111 MSG_BYPASSDIS = { string.char(0xAA) .. "pin" .. string.char(0x00, 0x00, 0x00, 0x00) .. "bypass" .. string.char(0x43), nil }, 103 112 MSG_DOWNLOAD = { string.char(0x24, 0x00, 0x00) .. pmDownloadCode.. string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0x3C }, 104 MSG_SETTIME = { string.char(0x46, 0xF8, 0x00 , 0x00) .. "time" .. string.char(0xFF, 0xFF), nil },113 MSG_SETTIME = { string.char(0x46, 0xF8, 0x00) .. "time" .. string.char(0xFF, 0xFF), nil }, 105 114 MSG_DL = { string.char(0x3E) .. "item" .. string.char(0xB0, 0x00, 0x00, 0x00, 0x00, 0x00), 0x3F}, 106 115 MSG_SER_TYPE = { string.char(0x5A, 0x30, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0x33}, … … 110 119 111 120 pmDownloadItem_t = { 112 MSG_DL_FORCECODE = string.char(0x11, 0x01, 0x02, 0x00), 113 MSG_DL_PHONENRS = string.char(0x36, 0x01, 0x20, 0x00), 114 MSG_DL_PINCODES = string.char(0xFA, 0x01, 0x10, 0x00), 115 MSG_DL_PANELFW = string.char(0x00, 0x04, 0x20, 0x00), 116 MSG_DL_SERIAL = string.char(0x30, 0x04, 0x08, 0x00), 117 MSG_DL_ZONES = string.char(0x00, 0x09, 0x78, 0x00), 118 MSG_DL_KEYFOBS = string.char(0x78, 0x09, 0x40, 0x00), 119 MSG_DL_X10NAMES = string.char(0x30, 0x0B, 0x10, 0x00), 120 MSG_DL_ZONENAMES = string.char(0x40, 0x0B, 0x1E, 0x00), 121 MSG_DL_EVENTLOG = string.char(0xDF, 0x04, 0x28, 0x03) 121 MSG_DL_FORCECODE = string.char(0x11, 0x01, 0x02, 0x00), 122 MSG_DL_PHONENRS = string.char(0x36, 0x01, 0x20, 0x00), 123 MSG_DL_PINCODES = string.char(0xFA, 0x01, 0x10, 0x00), 124 MSG_DL_PGMX10 = string.char(0x14, 0x02, 0xD5, 0x00), 125 MSG_DL_PANELFW = string.char(0x00, 0x04, 0x20, 0x00), 126 MSG_DL_SERIAL = string.char(0x30, 0x04, 0x08, 0x00), 127 MSG_DL_ZONES = string.char(0x00, 0x09, 0x78, 0x00), 128 MSG_DL_KEYFOBS = string.char(0x78, 0x09, 0x40, 0x00), 129 MSG_DL_SIRENS = string.char(0x60, 0x0A, 0x08, 0x00), 130 MSG_DL_X10NAMES = string.char(0x30, 0x0B, 0x10, 0x00), 131 MSG_DL_ZONENAMES = string.char(0x40, 0x0B, 0x1E, 0x00), 132 MSG_DL_EVENTLOG = string.char(0xDF, 0x04, 0x28, 0x03), 133 MSG_DL_ZONESTR = string.char(0x00, 0x19, 0x00, 0x02), 134 MSL_DL_ZONECUSTOM = string.char(0xA0, 0x1A, 0x50, 0x00), 135 MSG_DL_ALL = string.char(0x00, 0x00, 0x00, 0xFF) 122 136 } 123 137 … … 137 151 } 138 152 139 local pmLogEvent_t = { 153 local pmLogEvent_t = { 154 EN = { 140 155 "None", "Interior Alarm", "Perimeter Alarm", "Delay Alarm", "24h Silent Alarm", "24h Audible Alarm", 141 156 "Tamper", "Control Panel Tamper", "Tamper Alarm", "Tamper Alarm", "Communication Loss", "Panic From Keyfob", … … 159 174 "Freeze Alert Restore", "Human Cold Alert", "Human Cold Alert Restore", "Human Hot Alert", 160 175 "Human Hot Alert Restore", "Temperature Sensor Trouble", "Temperature Sensor Trouble Restore" 161 } 176 }, NL = { 177 "Geen", "In alarm", "In alarm", "In alarm", "In alarm", "In alarm", 178 "Sabotage alarm", "Systeem sabotage", "Sabotage alarm", "Add user", "Communicate fout", "Paniekalarm", 179 "Code bedieningspaneel paniek", "Dwang", "Bevestig alarm", "Successful U/L", "Probleem herstel", 180 "Herstel", "Herstel", "Herstel", "Herstel", "Herstel", 181 "Sabotage herstel", "Systeem sabotage herstel", "Sabotage herstel", "Sabotage herstel", "Communicatie herstel", 182 "Stop alarm", "Algemeen herstel", "Brand probleem herstel", "Systeem inactief", "Recent close", "Brand", "Brand herstel", 183 "Niet actief", "Noodoproep", "Remove user", "Controleer code", "Bevestig alarm", "Supervisie", 184 "Supervisie herstel", "Batterij laag", "Batterij OK", "230VAC uitval", "230VAC herstel", 185 "Controlepaneel batterij laag", "Controlepaneel batterij OK", "Radio jamming", "Radio herstel", 186 "Communicatie mislukt", "Communicatie hersteld", "Telefoonlijn fout", "Telefoonlijn herstel", 187 "Automatische test", "Zekeringsfout", "Zekering herstel", "Batterij laag", "Batterij OK", "Monteur reset", 188 "Accu vermist", "Batterij laag", "Batterij OK", "Supervisie", 189 "Supervisie herstel", "Lage batterij bevestiging", "Reinigen", "Probleem", "Batterij laag", "Batterij OK", 190 "230VAC uitval", "230VAC herstel", "Supervisie", "Supervisie herstel", "Gas alarm", "Gas herstel", 191 "Gas probleem", "Gas probleem herstel", "Lekkage alarm", "Lekkage herstel", "Probleem", "Probleem herstel", 192 "Deelschakeling", "Ingeschakeld", "Snel deelschakeling", "Snel ingeschakeld", "Uitgezet", "Inschakelfout (auto)", "Test gestart", 193 "Test gestopt", "Force aan", "Geheel in (auto)", "Onmiddelijk", "Overbruggen", "Inschakelfout", 194 "Log verzenden", "Systeem reset", "Installateur programmeert", "Foutieve code", "Overbruggen" 195 }} 162 196 163 197 local pmLogUser_t = { … … 173 207 } 174 208 175 local pmSysStatus_t = { 209 local pmSysStatus_t = { EN = { 176 210 "Disarmed", "Home Exit Delay", "Away Exit Delay", "Entry Delay", "Armed Home", "Armed Away", "User Test", 177 211 "Downloading", "Programming", "Installer", "Home Bypass", "Away Bypass", "Ready", "Not Ready", "??", "??", 178 212 "Disarmed Instant", "Home Exit Delay Instant", "Away Exit Delay Instant", "Entry Delay Instant", "Armed Home Instant", 179 213 "Armed Away Instant" 180 } 181 182 local pmSysStatusFlags_t = { 214 }} 215 216 local pmSysStatusFlags_t = { 217 EN = { 183 218 "Ready", "Alert in memory", "Trouble", "Bypass on", "Last 10 seconds", "Zone event", "Status changed", "Alarm event" 184 } 219 }, NL = { 220 "Klaar", "Alarm in geheugen", "Probleem", "Overbruggen aan", "Laatste 10 seconden", "Zone verstoord", "Status gewijzigd", 221 "Alarm actief" 222 }} 185 223 186 224 local pmArmed_t = { … … 199 237 } -- Not used: Night, NightInstant, Vacation 200 238 201 local pmEventType_t = { 202 "None", "Tamper Alarm", "Tamper Restore", "Open", "Closed", "Violated (Motion)", "Panic Alarm", "RF Jamming", "Tamper Open", 203 "Communication Failure", "Line Failure", "Fuse", "Not Active", "Low Battery", "AC Failure", "Fire Alarm", "Emergency", 204 "Siren Tamper", "Siren Tamper Restore", "Siren Low Battery", "Siren AC Fail" 205 } 239 local pmEventType_t = { 240 EN = { 241 "None", "Tamper Alarm", "Tamper Restore", "Open", "Closed", "Violated (Motion)", "Panic Alarm", "RF Jamming", 242 "Tamper Open", "Communication Failure", "Line Failure", "Fuse", "Not Active", "Low Battery", "AC Failure", 243 "Fire Alarm", "Emergency", "Siren Tamper", "Siren Tamper Restore", "Siren Low Battery", "Siren AC Fail" 244 }, NL = { 245 "Geen", "Sabotage alarm", "Sabotage herstel", "Open", "Gesloten", "Verstoord (beweging)", "Paniek alarm", "RF verstoring", 246 "Sabotage open", "Communicatie probleem", "Lijnfout", "Zekering", "Niet actief", "Lage batterij", "AC probleem", 247 "Brandalarm", "Noodoproep", "Sirene sabotage", "Sirene sabotage herstel", "Sirene lage batterij", "Sirene AC probleem" 248 }} 206 249 207 250 local pmPanelAlarmType_t = { … … 218 261 219 262 local pmPanelType_t = { 220 [ 0] = "PowerMax", [1] = "PowerMax+", [2] = "PowerMax Pro", [3] = "PowerMax Complete", [4] = "PowerMax Pro Part",221 [ 5] = "PowerMax Complete Part", [6] = "PowerMax Express", [7] = "PowerMaster10", [8] = "PowerMaster30"263 [1] = "PowerMax", [2] = "PowerMax+", [3] = "PowerMax Pro", [4] = "PowerMax Complete", [5] = "PowerMax Pro Part", 264 [6] = "PowerMax Complete Part", [7] = "PowerMax Express", [8] = "PowerMaster10", [9] = "PowerMaster30" 222 265 } 223 266 267 -- Config for each panel type (1-9) 268 local pmPanelConfig_t = { 269 CFG_PARTITIONS = { 0, 0, 0, 0, 3, 3, 0, 3, 3 }, 270 CFG_EVENTS = { 250, 250, 250, 250, 250, 250, 250, 250,1000 }, 271 CFG_KEYFOBS = { 8, 8, 8, 8, 8, 8, 8, 8, 32 }, 272 CFG_1WKEYPADS = { 8, 8, 8, 8, 8, 8, 8, 0, 0 }, 273 CFG_2WKEYPADS = { 2, 2, 2, 2, 2, 2, 2, 8, 32 }, 274 CFG_SIRENS = { 2, 2, 2, 2, 2, 2, 2, 4, 8 }, 275 CFG_USERCODES = { 8, 8, 8, 8, 8, 8, 8, 8, 48 }, 276 CFG_PROXTAGS = { 0, 0, 8, 0, 8, 8, 0, 8, 32 }, 277 CFG_WIRELESS = { 28, 28, 28, 28, 28, 28, 28, 30, 64 }, 278 CFG_WIRED = { 2, 2, 2, 2, 2, 2, 1, 1, 2 }, 279 CFG_ZONECUSTOM = { 0, 5, 5, 5, 5, 5, 5, 5, 5 } 280 } 281 224 282 local pmPanelName_t = { 225 283 ["0000"] = "PowerMax", ["0001"] = "PowerMax LT", ["0004"] = "PowerMax A", ["0005"] = "PowerMax 108", ["0006"] = "PowerMax LT 108", … … 275 333 276 334 local pmZoneType_t = { 277 "Non-Alarm", "Emergency", "Flood", "Gas", "Delay 1", "Delay 2", "Interior-Follow", "Perimeter", "Perimeter-Follow", 278 "24 Hours Silent", "24 Hours Audible", "Fire", "Interior" 279 } 280 335 EN = { 336 "Non-Alarm", "Emergency", "Flood", "Gas", "Delay 1", "Delay 2", "Interior-Follow", "Perimeter", 337 "Perimeter-Follow", "24 Hours Silent", "24 Hours Audible", "Fire", "Interior" 338 }, NL = { 339 "Geen alarm", "Noodtoestand", "Water", "Gas", "Vertraagd 1", "Vertraagd 2", "Interieur volg", "Omtrek", 340 "Omtrek volg", "24 uurs stil", "24 uurs luid", "Brand", "Interieur" 341 }} 342 343 -- Zone names are taken from the panel, so no langauage support needed 281 344 local pmZoneName_t = { 282 345 "Attic", "Back door", "Basement", "Bathroom", "Bedroom", "Child room", "Closet", "Den", "Dining room", "Downstairs", 283 346 "Emergency", "Fire", "Front door", "Garage", "Garage door", "Guest room", "Hall", "Kitchen", "Laundry room", "Living room", 284 "Master bathroom", "Master bedroom", "Office", "Upstairs", "Utility room", "Yard", "Custom 1", "Custom2", "Custom3", "Custom4",285 "Custom 5", "Not Installed"347 "Master bathroom", "Master bedroom", "Office", "Upstairs", "Utility room", "Yard", "Custom 1", "Custom 2", "Custom 3", 348 "Custom4", "Custom 5", "Not Installed" 286 349 } 287 350 … … 290 353 } 291 354 292 local pmZoneSensor_t = { 293 [0x3] = "PIR", [0x4] = "PIR", [0x5] = "Magnet", [0x6] = "Magnet", [0xA] = "Smoke" 355 -- Note: names need to match to VAR_xxx 356 local pmZoneSensor_t = { 357 [0x3] = "Motion", [0x4] = "Motion", [0x5] = "Magnet", [0x6] = "Magnet", [0xA] = "Smoke", [0xF] = "Siren" 294 358 } -- unknown to date: Control Panel, Push Button, Gas, Flood, Universal 295 359 296 -- Control debug to /var/log/cmh/LuaUPnP.log (taken from GE Caddx Panel) 297 function debug(s) 298 if (LOG_DEBUG) then 299 luup.log("POWERMAX: " .. s) 300 end 360 -- Create a system variable if it does not exist 361 function createIfNeeded(sid, var, newVal, id) 362 local curVal = luup.variable_get(sid, var, id) 363 if (curVal == nil) then 364 luup.variable_set(sid, var, newVal, id) 365 return true 366 end 367 return false 301 368 end 302 369 … … 318 385 end 319 386 end 387 end 388 389 -- Control debug to /var/log/cmh/LuaUPnP.log (taken from GE Caddx Panel) 390 function debug(s) 391 if (pmLogDebug) then 392 luup.log("POWERMAX: " .. s) 393 end 394 end 395 396 -- pmDumpSettings 397 function pmDumpSettings() 398 if (pmLogDebug) then 399 local dumpfile = pmFilenameSettings 400 local outf = io.open(dumpfile , 'w') 401 debug("Dumping PowerMax settings to file") 402 outf:write(string.format("PowerMax settings on %s\n", os.date('%Y-%m-%d %H:%M:%S'))) 403 for i = 0, 0xFF do 404 if (pmSettings_t[i] ~= nil) then 405 for j = 0, 0x0F do 406 local s = "" 407 outf:write(string.format("%08X: ", i * 0x100 + j * 0x10)) 408 for k = 1, 0x10 do 409 local byte = string.byte(pmSettings_t[i], j * 0x10 + k) 410 outf:write(string.format(" %02X", byte)) 411 s = (byte < 0x20 or (byte >= 0x80 and byte < 0xA0)) and (s .. ".") or (s .. string.char(byte)) 412 end 413 outf:write(" " .. s .. "\n") 414 end 415 end 416 end 417 outf:close() 418 end 419 end 420 421 -- PDUs can be logged in a file. We use this to discover new never before seen 422 -- PowerMax messages we need to decode and make sense of in long evenings... 423 function pmLogPdu(PDU, direction) 424 if (pmLogDebug) then 425 local logfile = pmFilenameLog 426 -- empty file if it reaches 250kb 427 local outf = io.open(logfile , 'a') 428 local filesize = outf:seek("end") 429 outf:close() 430 if (filesize > 250000) then 431 local outf = io.open(logfile , 'w') 432 outf:write('') 433 outf:close() 434 end 435 436 local outf = io.open(logfile, 'a') 437 outf:write(string.format("%s %s %s %s\n", os.date('%Y-%m-%d %H:%M:%S'), os.time(), direction, PDU)) 438 outf:close() 439 end 320 440 end 321 441 … … 380 500 pmPowerlinkMode = true 381 501 luup.call_timer("pmCheckKeepAlive", 1, "1m", "", "") 382 pmSendMessage(pmSendMsg_t.MSG_DL, { item = pmDownloadItem_t.MSG_DL_FORCECODE }) -- Request the forced disarm code 383 pmSendMessage(pmSendMsg_t.MSG_DL, { item = pmDownloadItem_t.MSG_DL_PANELFW }) -- Request the panel FW 384 pmSendMessage(pmSendMsg_t.MSG_DL, { item = pmDownloadItem_t.MSG_DL_SERIAL }) -- Request panel serial nr. 385 pmSendMessage(pmSendMsg_t.MSG_DL, { item = pmDownloadItem_t.MSG_DL_PINCODES }) -- Request pin codes 386 pmSendMessage(pmSendMsg_t.MSG_DL, { item = pmDownloadItem_t.MSG_DL_ZONES }) -- Request zone info 387 pmSendMessage(pmSendMsg_t.MSG_DL, { item = pmDownloadItem_t.MSG_DL_ZONENAMES }) -- Request zone names 388 pmSendMessage(pmSendMsg_t.MSG_EXIT) -- Exit download mode 389 luup.variable_set(PANEL_SID, "PowerlinkMode", "Powerlink", panel_device) 390 end 391 392 -- pmReadPanelSettings 502 pmSendMessage("MSG_DL", { item = pmDownloadItem_t.MSG_DL_PANELFW }) -- Request the panel FW 503 pmSendMessage("MSG_DL", { item = pmDownloadItem_t.MSG_DL_ZONESTR }) -- Read the names of the zones 504 pmSendMessage("MSG_START") -- Start sending all relevant settings please 505 pmSendMessage("MSG_EXIT") -- Exit download mode 506 luup.variable_set(PANEL_SID, "PowerlinkMode", "Powerlink", pmPanelDev) 507 end 508 509 -- pmReadPanelSettings: update settings after coming out of programming mode 393 510 function pmReadPanelSettings() 394 pmSendMessage(pmSendMsg_t.MSG_SER_TYPE) -- Request panel settings 395 pmSendMessage(pmSendMsg_t.MSG_DOWNLOAD) -- Send our download code to the Powermax 396 pmSendMessage(pmSendMsg_t.MSG_START) -- Start sending please 397 pmSendMessage(pmSendMsg_t.MSG_EXIT) -- Exit download mode 511 if (pmPowerlinkMode == true) then 512 pmSendMessage("MSG_DOWNLOAD") -- Send our download code to the Powermax 513 pmSendMessage("MSG_DL", { item = pmDownloadItem_t.MSG_DL_ZONESTR }) 514 pmSendMessage("MSG_START") -- Start sending please 515 pmSendMessage("MSG_EXIT") -- Exit download mode 516 end 398 517 end 399 518 … … 405 524 -- Let Powermax know we are alive (and reset Powerlink communication error) 406 525 debug("Clear Powerlink communication error") 407 pmSendMessage(pmSendMsg_t.MSG_RESTORE) 526 pmSendMessage("MSG_RESTORE") 527 pmPowerlinkRetry = pmPowerlinkRetry + 1 408 528 if (pmPowerlinkRetry == PL_RETRIES) then 409 529 pmPowerlinkMode = false 410 luup.variable_set(PANEL_SID, "PowerlinkMode", "Standard", p anel_device)530 luup.variable_set(PANEL_SID, "PowerlinkMode", "Standard", pmPanelDev) 411 531 return 412 else413 pmPowerlinkRetry = pmPowerlinkRetry + 1414 532 end 415 533 end … … 423 541 for i = 1, 30 do 424 542 local s = string.format("Z%02d", i) 425 local child = findChild(p anel_device, s)543 local child = findChild(pmPanelDev, s) 426 544 if (child == nil) then 427 545 -- debug("no zone " .. s) … … 439 557 end 440 558 441 -- Initialises the panel and creates necessary child devices 559 -- pmCreateDevice 560 function pmCreateDevice(deviceList, altid, deviceName, zoneName, zoneType) 561 local devVar = "VAR_" .. string.upper(deviceName) 562 local devInit = pmDevices_t[devVar] 563 564 assert(devInit ~= nil) 565 local setVars = devInit[4] 566 if (type(altid) == "number") then 567 altid = string.format("%s-%d", deviceName, altid) 568 elseif (string.sub(altid, 1, 1) == "Z") then 569 local wirelessCnt = pmPanelConfig_t.CFG_WIRELESS[pmPanelTypeNr] 570 local nr = tonumber(string.sub(altid, 2)) 571 if (nr > wirelessCnt) then 572 setVars = CON_SENSOR_INIT -- wired zone 573 end 574 end 575 if (zoneName == nil) or (zoneName == "") then 576 zoneName = altid 577 end 578 if (zoneType ~= nil) and (zoneType ~= "") then 579 zoneName = zoneName .. " (" .. zoneType .. ")" 580 else 581 zoneName = zoneName .. " (PowerMax)" 582 end 583 pmMessage("Adding device " .. altid .. " (" .. zoneName .. ")", 4) 584 luup.chdev.append(pmPanelDev, deviceList, altid, zoneName, devInit[1], devInit[2], devInit[3], setVars, devInit[5]) 585 end 586 587 -- Initialises the panel, handlers etc. 442 588 function pmStartup(lul_device) 443 panel_device = lul_device 444 445 luup.log("POWERMAX: starting ... device #"..tostring(panel_device), 10) 446 447 updateIfNeeded(PANEL_SID, "PowermaxVersion", POWERMAX_VERSION, panel_device) 448 updateIfNeeded(PANEL_SID, "PowerlinkMode", "Unknown", panel_device) 449 450 if (luup.io.is_connected(panel_device) == false) then 589 pmPanelDev = lul_device 590 591 luup.log("POWERMAX: starting ... device #" .. tostring(pmPanelDev), 10) 592 593 updateIfNeeded(PANEL_SID, "PluginVersion", PLUGIN_VERSION, pmPanelDev) 594 createIfNeeded(PANEL_SID, "PluginDebug", "0", pmPanelDev) 595 createIfNeeded(PANEL_SID, "AutoCreate", "1", pmPanelDev) 596 createIfNeeded(PANEL_SID, "DoorZones", "", pmPanelDev) 597 createIfNeeded(PANEL_SID, "MotionZones", "", pmPanelDev) 598 createIfNeeded(PANEL_SID, "SmokeZones", "", pmPanelDev) 599 createIfNeeded(PANEL_SID, "Devices", "", pmPanelDev) 600 updateIfNeeded(PANEL_SID, "PowerlinkMode", "Unknown", pmPanelDev) 601 createIfNeeded(PANEL_SID, "PanelStatusCode", "", pmPanelDev) 602 createIfNeeded(PANEL_SID, "PanelStatusData", "", pmPanelDev) 603 createIfNeeded(PANEL_SID, "PanelAlarmType", "", pmPanelDev) 604 createIfNeeded(PANEL_SID, "PanelTroubleType", "", pmPanelDev) 605 606 pmLogDebug = (luup.variable_get(PANEL_SID, "PluginDebug", pmPanelDev) ~= "0") 607 608 if (luup.io.is_connected(pmPanelDev) == false) then 451 609 pmMessage("Please select the Serial Port for the PowerMax", 2) 452 610 return false … … 466 624 pmReceiveMsg_t[0xAB][2] = pmHandlePowerlink 467 625 468 child_devices = luup.chdev.start(panel_device)469 470 pmMessage("Adding partition device", 4)471 local devInit = pmDevices_t.VAR_ALARM472 luup.chdev.append(panel_device, child_devices, "Partition-1", "Partition-1 (Powermax)", devInit[1], devInit[2], devInit[3], devInit[4], devInit[5])473 partition_device = findChild(panel_device, "Partition-1")474 475 pmMessage("Adding zone devices", 4)476 477 local doorZones = luup.variable_get(PANEL_SID, "DoorZones", panel_device)478 if (doorZones == nil) then479 luup.variable_set(PANEL_SID, "DoorZones", "", panel_device)480 doorZones = ""481 end482 483 local motionZones = luup.variable_get(PANEL_SID, "MotionZones", panel_device)484 if (motionZones == nil) then485 luup.variable_set(PANEL_SID, "MotionZones", "", panel_device)486 motionZones = ""487 end488 489 local smokeZones = luup.variable_get(PANEL_SID, "SmokeZones", panel_device)490 if (smokeZones == nil) then491 luup.variable_set(PANEL_SID, "SmokeZones", "", panel_device)492 smokeZones = ""493 end494 495 local x10Devices = luup.variable_get(PANEL_SID, "X10Devices", panel_device)496 if (x10Devices == nil) then497 luup.variable_set(PANEL_SID, "X10Devices", "", panel_device)498 x10Devices = ""499 end500 501 local PGM = luup.variable_get(PANEL_SID, "PGM", panel_device)502 if (PGM == "0" or PGM == "1") then503 -- Do nothing, value is correct504 elseif ((PGM == "true") or (PGM == "yes")) then505 luup.variable_set(PANEL_SID, "PGM", "1", panel_device)506 PGM = "1"507 else508 luup.variable_set(PANEL_SID, "PGM", "0", panel_device)509 PGM = "0"510 end511 512 for i = 1, 30 do513 s = string.format("Z%02d", i)514 local setVars = devInit[4]515 if (i > 28) then516 setVars = CON_SENSOR_INIT -- zones 29 & 30 are wired517 end518 if (string.find(doorZones, s) ~= nil) then519 debug("adding door zone " .. s)520 local devInit = pmDevices_t.VAR_DOOR521 luup.chdev.append(panel_device, child_devices, s, s.." (Powermax)", devInit[1], devInit[2], devInit[3], setVars, devInit[5])522 elseif (string.find (motionZones, s) ~= nil) then523 debug("adding motion zone " .. s)524 local devInit = pmDevices_t.VAR_MOTION525 luup.chdev.append(panel_device, child_devices, s, s.." (Powermax)", devInit[1], devInit[2], devInit[3], setVars, devInit[5])526 elseif (string.find (smokeZones, s) ~= nil) then527 debug("adding smoke zone " .. s)528 local devInit = pmDevices_t.VAR_SMOKE529 luup.chdev.append(panel_device, child_devices, s, s.." (Powermax)", devInit[1], devInit[2], devInit[3], setVars, devInit[5])530 end531 end532 533 for i = 0, 15 do534 if (i == 0) then535 s = "PGM"536 if (PGM == "1") then537 debug("adding PGM output")538 local devInit = pmDevices_t.VAR_SWITCH539 luup.chdev.append(panel_device, child_devices, s, s.." (Powermax)", devInit[1], devInit[2], devInit[3], devInit[4], devInit[5])540 end541 else542 s = string.format("X%02d", i)543 local pos = string.find(x10Devices, s)544 if (pos ~= nil) then545 debug("adding x10 device " .. s)546 local devInit547 if (string.sub(x10Devices, pos + 3, pos + 3) == "d") then548 devInit = pmDevices_t.VAR_DIM549 else550 devInit = pmDevices_t.VAR_SWITCH551 end552 luup.chdev.append(panel_device, child_devices, s, s.." (Powermax)", devInit[1], devInit[2], devInit[3], devInit[4], devInit[5])553 end554 end555 local x10_device = findChild(panel_device, s)556 if (x10_device ~= nil) then557 local x10_dev_nr = luup.variable_get(PANEL_SID, "X10DeviceNr", x10_device)558 if (x10_dev_nr == nil) then559 x10_dev_nr = string.format("%04x", 2 ^ i)560 luup.variable_set(PANEL_SID, "X10DeviceNr", x10_dev_nr, x10_device)561 end562 end563 end564 565 luup.chdev.sync(panel_device,child_devices)566 626 luup.call_timer("pmMotionOff", 1, "1m", "", "") 567 pmSendMessage(pmSendMsg_t.MSG_INIT) 568 pmSendMessage(pmSendMsg_t.MSG_STATUS) 569 --pmReadPanelSettings() 570 pmSendMessage(pmSendMsg_t.MSG_DOWNLOAD) -- Send our download code to the Powermax 627 pmSendMessage("MSG_INIT") 628 pmSendMessage("MSG_INIT") -- Two times, in case in wrong state 629 pmSendMessage("MSG_RESTORE") -- Also sends status 630 pmSendMessage("MSG_SER_TYPE") -- Request panel type & serial (without being in download mode) 631 pmSendMessage("MSG_DOWNLOAD") -- Send our download code to the Powermax 571 632 -- If we get a NACK, then the download code is not valid (not enrolled) 572 633 end 573 634 574 -- Convert a PIN given as string in the PIN PDU format as used in messages to powermax635 -- pmGetPin: Convert a PIN given as string in the PIN PDU format as used in messages to powermax 575 636 function pmGetPin(pin) 576 637 local pinPDU … … 589 650 return pinPDU 590 651 end 591 592 -- PDUs are logged in a file. We use this to discover new never before seen 593 -- PowerMax messages we need to decode and make sense of in long evenings 594 function pmLogPdu(PDU, direction) 595 local logfile = '/var/log/cmh/powermax_pdu.txt' 596 -- empty file if it reaches 250kb 597 local outf = io.open(logfile , 'a') 598 local filesize = outf:seek("end") 599 outf:close() 600 if (filesize > 250000) then 601 local outf = io.open(logfile , 'w') 602 outf:write('') 603 outf:close() 604 end 605 606 local outf = io.open(logfile, 'a') 607 outf:write(string.format("%s %s %s %s\n", os.date('%Y-%m-%d %H:%M:%S'), os.time(), direction, PDU)) 608 outf:close() 652 653 -- pmWriteSettings: add a certain setting to the settings table 654 function pmWriteSettings(page, index, setting) 655 local len = string.len(setting) + 1 656 local wrap = (index + len - 0x100) 657 local sett = { "", "" } 658 local i 659 assert(len <= 0xB1) 660 if (wrap > 0) then 661 sett[1] = string.sub(setting, 1, len - wrap) 662 sett[2] = string.sub(setting, len - wrap + 1, len) 663 wrap = 1 664 else 665 sett[1] = setting 666 wrap = 0 667 end 668 for i = 0, wrap do 669 if (pmSettings_t[page + i] == nil) then 670 pmSettings_t[page + i] = string.rep(string.char(0xFF), 0x100) 671 end 672 len = string.len(sett[i + 1]) + 1 673 if (i == 1) then 674 index = 0 675 end 676 pmSettings_t[page + i] = string.sub(pmSettings_t[page + i], 1, index) .. sett[i + 1] .. string.sub(pmSettings_t[page + i], index + len, 0x100) 677 end 678 end 679 680 -- pmReadSettings 681 function pmReadSettings(item) 682 local index = string.byte(item, 1) + 1 683 local page = string.byte(item, 2) 684 local len = string.byte(item, 3) + 0x100 * string.byte(item, 4) 685 local s = "" 686 if (pmSettings_t[page] ~= nil) then 687 while (len > 0) do 688 local str = string.sub(pmSettings_t[page], index, index + len) 689 s = s .. str 690 page = page + 1 691 index = 1 692 len = len - string.len(str) 693 end 694 end 695 return s 696 end 697 698 -- pmProcessSetting 699 function pmProcessSettings() 700 local i, setting 701 local zone_t = {} 702 local x10_t = {} 703 local doorZoneStr = "" 704 local motionZoneStr = "" 705 local smokeZoneStr = "" 706 local deviceStr = "" 707 local childDevices = luup.chdev.start(pmPanelDev) 708 local autoCreate = (luup.variable_get(PANEL_SID, "AutoCreate", pmPanelDev) == "1") 709 710 local model = pmPanelType_t[pmPanelTypeNr] 711 updateIfNeeded(PANEL_SID, "PanelType", model, pmPanelDev) 712 713 local zoneCnt = pmPanelConfig_t.CFG_WIRELESS[pmPanelTypeNr] + pmPanelConfig_t.CFG_WIRED[pmPanelTypeNr] 714 local customCnt = pmPanelConfig_t.CFG_ZONECUSTOM[pmPanelTypeNr] 715 local userCnt = pmPanelConfig_t.CFG_USERCODES[pmPanelTypeNr] 716 local partitionCnt = pmPanelConfig_t.CFG_PARTITIONS[pmPanelTypeNr] 717 local sirenCnt = pmPanelConfig_t.CFG_SIRENS[pmPanelTypeNr] 718 local keypad1wCnt = pmPanelConfig_t.CFG_1WKEYPADS[pmPanelTypeNr] 719 local keypad2wCnt = pmPanelConfig_t.CFG_2WKEYPADS[pmPanelTypeNr] 720 721 pmDumpSettings() 722 723 for i = 1, 1 do -- TODO: '1 + partitionCnt' for multiple partition support 724 pmCreateDevice(childDevices, i, "Partition") 725 local s = string.format("Partition-%d", i) 726 pmPartitionDev_t[i] = findChild(pmPanelDev, s) 727 end 728 729 pmMessage("Adding zone devices", 4) 730 if (pmPowerlinkMode == true) then 731 -- Process zone names of this panel 732 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_ZONESTR) 733 for i = 1, 26 + customCnt do 734 local s = string.sub(setting, (i - 1) * 0x10 + 1, i * 0x10):gsub("%s*$", "") 735 if (string.byte(s, 1) ~= 0xFF) then 736 pmZoneName_t[i] = string.sub(s, 1, 1) .. string.lower(string.sub(s, 2, 0x0F)) 737 end 738 end 739 740 -- PowerLink mode 741 debug("Processing forced disarm code") 742 pmForcedDisarmCode = pmReadSettings(pmDownloadItem_t.MSG_DL_FORCECODE) 743 744 debug("Processing pin codes") 745 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_PINCODES) 746 for i = 1, userCnt do 747 pmPincode_t[i] = string.sub(setting, 2 * i - 1, 2 * i) 748 end 749 750 debug("Processing software version") 751 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_PANELFW) 752 local panelEprom = string.sub(setting, 0x01, 0x10) 753 local panelSoftware = string.sub(setting, 0x11, 0x20) 754 debug(string.format("EPROM: %s; SW: %s", panelEprom, panelSoftware)) 755 updateIfNeeded(PANEL_SID, "PanelEprom", panelEprom, pmPanelDev) 756 updateIfNeeded(PANEL_SID, "PanelSoftware", panelSoftware, pmPanelDev) 757 758 debug("Processing serial and panel type") 759 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_SERIAL) 760 local idx = string.format("%02x%02x", string.byte(setting, 8), string.byte(setting, 7)) 761 local pmPanelName = pmPanelName_t[idx] or "UNKNOWN" 762 local pmPanelSerial = "" 763 for i = 0, 5 do 764 local nr = string.byte(setting, i + 1) 765 local s = (nr == 0xFF) and "." or string.format("%02X", nr) 766 pmPanelSerial = pmPanelSerial .. s 767 end 768 debug(string.format("Panel %s with serial %s", pmPanelName, pmPanelSerial)) 769 updateIfNeeded(PANEL_SID, "PanelName", pmPanelName, pmPanelDev) 770 updateIfNeeded(PANEL_SID, "PanelSerial", pmPanelSerial, pmPanelDev) 771 772 debug("Processing zone information") 773 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_ZONES) 774 local zoneNames = pmReadSettings(pmDownloadItem_t.MSG_DL_ZONENAMES) 775 for i = 1, zoneCnt do 776 local zoneEnrolled = (string.sub(setting, i * 4 - 3, i * 4 - 1) ~= string.char(0, 0, 0)) 777 local zoneName = pmZoneName_t[string.byte(zoneNames, i) + 1] 778 if (zoneEnrolled == true) then 779 local zoneInfo = string.byte(setting, i * 4) 780 local zoneType = pmZoneType_t[pmLang][bitw.band(zoneInfo, 0x0F) + 1] 781 local zoneChime = pmZoneChime_t[bitw.rshift(zoneInfo, 4) + 1] 782 local sensorType = string.byte(setting, i * 4 - 1) 783 local sensorName = pmZoneSensor_t[bitw.band(sensorType, 0xF)] or "UNKNOWN" 784 debug(string.format("Zone %02d: %s (%s; sensor type = %02X [%s])" , i, zoneType, zoneChime, sensorType, sensorName)) 785 zone_t[i] = { zoneName, zoneType } 786 if (sensorName == "Magnet") then 787 doorZoneStr = string.format("%s,Z%02d", doorZoneStr, i) 788 elseif (sensorName == "Motion") then 789 motionZoneStr = string.format("%s,Z%02d", motionZoneStr, i) 790 elseif (sensorName == "Smoke") then 791 smokeZoneStr = string.format("%s,Z%02d", smokeZoneStr, i) 792 end 793 end 794 end 795 debug("Processing PGM/X10 information") 796 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_PGMX10) 797 local x10Names = pmReadSettings(pmDownloadItem_t.MSG_DL_X10NAMES) 798 for i = 0, 15 do 799 local enabled = false 800 local x10Name = 0x1F 801 for j = 0, 8 do 802 enabled = enabled or (string.byte(setting, 6 + i + j * 0x10) ~= 0) 803 end 804 if (i > 0) then 805 x10Name = string.byte(x10Names, i) 806 x10_t[i] = pmZoneName_t[x10Name + 1] 807 end 808 if (enabled == true) or (x10Name ~= 0x1F) then 809 if (i == 0) then 810 deviceStr = deviceStr .. ",PGM" 811 else 812 deviceStr = string.format("%s,X%02d", deviceStr, i) 813 end 814 end 815 end 816 -- TODO: automatic keypad detection 817 debug("Processing siren information") 818 setting = pmReadSettings(pmDownloadItem_t.MSG_DL_SIRENS) 819 for i = 1, sirenCnt do 820 local sirenEnrolled = (string.sub(setting, i * 4 - 3, i * 4 - 1) ~= string.char(0, 0, 0)) 821 if (sirenEnrolled == true) then 822 deviceStr = string.format("%s,S%02d", deviceStr, i) 823 end 824 end 825 end 826 827 -- Use variables if AutoCreate is false or not in Powerlink mode, otherwise use what we read in the settings 828 local doorZones = doorZoneStr 829 local motionZones = motionZoneStr 830 local smokeZones = smokeZoneStr 831 local devices = deviceStr 832 if (autoCreate == false) or (pmPowerlinkMode == false) then 833 doorZones = luup.variable_get(PANEL_SID, "DoorZones", pmPanelDev) 834 motionZones = luup.variable_get(PANEL_SID, "MotionZones", pmPanelDev) 835 smokeZones = luup.variable_get(PANEL_SID, "SmokeZones", pmPanelDev) 836 devices = luup.variable_get(PANEL_SID, "Devices", pmPanelDev) 837 elseif (pmPowerlinkMode == true) then 838 updateIfNeeded(PANEL_SID, "DoorZones", string.sub(doorZoneStr, 2), pmPanelDev) 839 updateIfNeeded(PANEL_SID, "MotionZones", string.sub(motionZoneStr, 2), pmPanelDev) 840 updateIfNeeded(PANEL_SID, "SmokeZones", string.sub(smokeZoneStr, 2), pmPanelDev) 841 updateIfNeeded(PANEL_SID, "Devices", string.sub(deviceStr, 2), pmPanelDev) 842 end 843 844 -- Start adding zones 845 local zoneName, zoneType 846 for i = 1, zoneCnt do 847 local s = string.format("Z%02d", i) 848 if (zone_t[i] ~= nil) then 849 zoneName = zone_t[i][1] 850 zoneType = zone_t[i][2] 851 else 852 zoneName = nil 853 zoneType = nil 854 end 855 if (string.find(doorZones, s) ~= nil) then 856 pmCreateDevice(childDevices, s, "Magnet", zoneName, zoneType) 857 elseif (string.find (motionZones, s) ~= nil) then 858 pmCreateDevice(childDevices, s, "Motion", zoneName, zoneType) 859 elseif (string.find (smokeZones, s) ~= nil) then 860 pmCreateDevice(childDevices, s, "Smoke", zoneName, zoneType) 861 end 862 end 863 864 -- Add PGM and X10 devices 865 for i = 0, 15 do 866 if (i == 0) then 867 if (string.find(devices, "PGM")) then 868 pmCreateDevice(childDevices, "PGM", "Switch", "PGM") 869 end 870 else 871 s = string.format("X%02d", i) 872 local pos = string.find(devices, s) 873 if (pos ~= nil) then 874 local devInit 875 if (string.sub(devices, pos + 3, pos + 3) == "d") then 876 pmCreateDevice(childDevices, s, "Dim", x10_t[i], s) 877 else 878 pmCreateDevice(childDevices, s, "Switch", x10_t[i], s) 879 end 880 end 881 end 882 local x10_device = findChild(pmPanelDev, s) 883 if (x10_device ~= nil) then 884 x10_dev_nr = string.format("%04x", 2 ^ i) 885 createIfNeeded(PANEL_SID, "X10DeviceNr", x10_dev_nr, x10_device) 886 end 887 end 888 889 -- Add sirens 890 for i = 1, sirenCnt do 891 local sirenEnrolled = (string.find(devices, string.format("S%02d", i)) ~= nil) 892 if (sirenEnrolled == true) then 893 pmCreateDevice(childDevices, i, "Siren") 894 end 895 end 896 897 -- Add keypads 898 for i = 1, keypad1wCnt do 899 local keypadEnrolled = (string.find(devices, string.format("K1%d", i)) ~= nil) 900 if (keypadEnrolled == true) then 901 pmCreateDevice(childDevices, i, "Keypad", nil, "1-way") 902 end 903 end 904 905 for i = 1, keypad2wCnt do 906 local keypadEnrolled = (string.find(devices, string.format("K2%d", i)) ~= nil) 907 if (keypadEnrolled == true) then 908 pmCreateDevice(childDevices, i, "Keypad", nil, "2-way") 909 end 910 end 911 luup.chdev.sync(pmPanelDev, childDevices) 912 pmMessage("Ready for use", 2) 609 913 end 610 914 … … 654 958 timeout = true 655 959 else 960 msg = pmSendMsg_t[msg] 961 assert(msg ~= nil) 656 962 outPdu = string.char(0x0D) .. msg[1] .. string.char(0x00, 0x0A) 657 963 response = (msg[2] == nil) and "" or string.char(msg[2]) … … 661 967 outPdu = string.gsub(outPdu, fnd, rpl) 662 968 end 969 end 970 971 if (string.byte(outPdu, 2) == 0x3E) then 972 local cnt = (string.byte(outPdu, 5)) + 0x100 * string.byte(outPdu, 6) 973 response = string.rep(response, math.floor(cnt / 0xB0) + 1) 663 974 end 664 975 end … … 726 1037 pmExpectedResponse = string.sub(pmExpectedResponse, 2) 727 1038 if (firstExpectedResponse ~= msgType) then 728 debug(string.format("*** Re-sending PDU (expected %02X got %02X) ***", firstExpectedResponse, msgType))729 if (pmSendMsgRetries == MSG_RETRIES) then730 pm ExpectedResponse = ""731 pm SendMessage(pmSendMsg_t.MSG_RESTORE)1039 if (pmSendMsgRetries == 0) then 1040 debug(string.format("*** Waiting for next PDU (expected %02X got %02X) ***", firstExpectedResponse, msgType)) 1041 pmSendMsgRetries = 1 -- don't resend immediately - first wait for the next response 1042 pmExpectedResponse = string.char(firstExpectedResponse) .. pmExpectedResponse 732 1043 else 733 pmSendMsgRetries = pmSendMsgRetries + 1 734 pmSendMessage(-1) 1044 debug(string.format("*** Re-sending PDU (expected %02X got %02X) ***", firstExpectedResponse, msgType)) 1045 if (pmSendMsgRetries == MSG_RETRIES) then 1046 pmExpectedResponse = "" 1047 pmSendMessage("MSG_INIT") 1048 else 1049 pmSendMsgRetries = pmSendMsgRetries + 1 1050 pmSendMessage(-1) 1051 end 735 1052 end 736 1053 else … … 741 1058 if (pmExpectedResponse == "") then 742 1059 debug("*** Sending next PDU in queue ***") 1060 luup.sleep(10) 743 1061 pmSendMessage(nil) 744 1062 end … … 753 1071 -- pmHandleAck (0x02) 754 1072 function pmHandleAck() 1073 local lastSendMsgType = string.byte(pmLastSendMsg, 2) 1074 1075 if (lastSendMsgType == 0x0F) then 1076 pmProcessSettings() 1077 end 755 1078 return true 756 1079 end … … 759 1082 function pmHandleTimeout() 760 1083 debug("Powermax sends timeout") 761 pmExpectedResponse = ""762 pmSendMessage( pmSendMsg_t.MSG_EXIT)1084 pmExpectedResponse = string.char(0x06) 1085 pmSendMessage("MSG_EXIT") 763 1086 return true 764 1087 end … … 773 1096 elseif (lastSendMsgType == 0x24) then 774 1097 pmPowerlinkMode = false 775 luup.variable_set(PANEL_SID, "PowerlinkMode", "Standard", p anel_device)1098 luup.variable_set(PANEL_SID, "PowerlinkMode", "Standard", pmPanelDev) 776 1099 pmMessage("Vera PowerLink not enrolled.", 2) 777 1100 end … … 789 1112 -- pmHandleSettings (0x33) 790 1113 function pmHandleSettings() 791 local row= string.byte(pmIncomingPdu, 3)1114 local index = string.byte(pmIncomingPdu, 3) 792 1115 local page = string.byte(pmIncomingPdu, 4) 793 1116 local lastSendMsgType = string.byte(pmLastSendMsg, 2) 794 debug(string.format("Received Powermax setting page %02X row %02X", page, row))1117 debug(string.format("Received Powermax setting page %02X index %02X", page, index)) 795 1118 if (lastSendMsgType == 0x0A) then 796 1119 pmExpectedResponse = pmExpectedResponse .. string.char(0x33) -- we're not done; keep them coming 797 1120 end 798 pm Settings_t[page] = pmSettings_t[page] .. string.sub(pmIncomingPdu, 5, 12)1121 pmWriteSettings(page, index, string.sub(pmIncomingPdu, 5, 12)) 799 1122 return true 800 1123 end … … 802 1125 -- pmHandleInfo (0x3C) 803 1126 function pmHandleInfo() 804 local id2 = string.byte(pmIncomingPdu, 8) 805 local model = pmPanelType_t[id2] 806 updateIfNeeded(PANEL_SID, "PanelType", model, panel_device) 1127 pmPanelTypeNr = string.byte(pmIncomingPdu, 8) + 1 1128 local model = pmPanelType_t[pmPanelTypeNr] 1129 updateIfNeeded(PANEL_SID, "PanelType", model, pmPanelDev) 1130 -- TODO: update DL messages (length) based on panel type 807 1131 pmPowerlinkEnrolled() 808 1132 return true … … 813 1137 local idx = string.byte(pmIncomingPdu, 3) 814 1138 local page = string.byte(pmIncomingPdu, 4) 815 local idxPage = string.sub(pmIncomingPdu, 3, 4)816 1139 local len = string.byte(pmIncomingPdu, 5) 817 local i818 1140 debug(string.format("Received Powermax setting page %02X index %02X", page, idx)) 819 if (idxPage == string.sub(pmDownloadItem_t.MSG_DL_FORCECODE, 1, 2)) then 820 debug("Reading forced disarm code") 821 pmForcedDisarmCode = string.sub(pmIncomingPdu, 6, 7) 822 elseif (idxPage == string.sub(pmDownloadItem_t.MSG_DL_PINCODES, 1, 2)) then 823 debug("Reading pin codes") 824 for i = 1, 8 do 825 pmPincode_t[i] = string.sub(pmIncomingPdu, 4 + 2 * i, 5 + 2 * i) 826 end 827 elseif (idxPage == string.sub(pmDownloadItem_t.MSG_DL_PANELFW, 1, 2)) then 828 debug("Reading software version") 829 local panelEprom = string.sub(pmIncomingPdu, 0x06, 0x15) 830 local panelSoftware = string.sub(pmIncomingPdu, 0x16, 0x25) 831 debug(string.format("EPROM: %s; SW: %s", panelEprom, panelSoftware)) 832 updateIfNeeded(PANEL_SID, "PanelEprom", panelEprom, panel_device) 833 updateIfNeeded(PANEL_SID, "PanelSoftware", panelSoftware, panel_device) 834 elseif (idxPage == string.sub(pmDownloadItem_t.MSG_DL_SERIAL, 1, 2)) then 835 debug("Reading serial and panel type") 836 local idx = string.format("%02x%02x", string.byte(pmIncomingPdu, 0x0D), string.byte(pmIncomingPdu, 0x0C)) 837 pmPanelName = pmPanelName_t[idx] or "UNKNOWN" 838 pmPanelSerial = "" 839 for i = 0, 5 do 840 local nr = string.byte(pmIncomingPdu, 0x06 + i) 841 local s = (nr == 0xFF) and "." or string.format("%02X", nr) 842 pmPanelSerial = pmPanelSerial .. s 843 end 844 debug(string.format("Panel %s with serial %s", pmPanelName, pmPanelSerial)) 845 updateIfNeeded(PANEL_SID, "PanelName", pmPanelName, panel_device) 846 updateIfNeeded(PANEL_SID, "PanelSerial", pmPanelSerial, panel_device) 847 elseif (idxPage == string.sub(pmDownloadItem_t.MSG_DL_ZONES, 1, 2)) then 848 debug("Reading zone information") 849 for i = 1, 30 do 850 local zoneEnrolled = (string.sub(pmIncomingPdu, 2 + i * 4, 4 + i * 4) ~= string.char(0, 0, 0)) 851 if (zoneEnrolled == true) then 852 local zoneInfo = string.byte(pmIncomingPdu, 5 + i * 4) 853 local zoneType = pmZoneType_t[bitw.band(zoneInfo, 0x0f) + 1] 854 local zoneChime = pmZoneChime_t[bitw.rshift(zoneInfo, 4) + 1] 855 local sensorType = string.byte(pmIncomingPdu, 4 + i * 4) 856 local sensorName = pmZoneSensor_t[bitw.band(sensorType, 0xF)] or "UNKNOWN" 857 debug(string.format("Zone %02d: %s (%s; sensor type = %02X [%s])" , i, zoneType, zoneChime, sensorType, sensorName)) 858 end 859 end 860 elseif (idxPage == string.sub(pmDownloadItem_t.MSG_DL_ZONENAMES, 1, 2)) then 861 debug("Reading zone name information") 862 for i = 1, 30 do 863 local zoneName = pmZoneName_t[string.byte(pmIncomingPdu, 5 + i) + 1] 864 debug(string.format("Zone %02d: %s" , i, zoneName)) 865 end 866 end 1141 pmWriteSettings(page, idx, string.sub(pmIncomingPdu, 6, 5 + len)) 867 1142 end 868 1143 … … 885 1160 local eventType = string.byte(pmIncomingPdu, 12) 886 1161 pmEventLog = pmEventLog .. string.format("\r\n%02d/%02d/%d %02d:%02d:%02d ", dayNum, monNum, yerNum, horNum, minNum, secNum) 887 pmEventLog = pmEventLog .. (pmLogUser_t[eventZone +1] or "UNKNOWN")1162 pmEventLog = pmEventLog .. (pmLogUser_t[eventZone + 1] or "UNKNOWN") 888 1163 pmEventLog = pmEventLog .. " " 889 pmEventLog = pmEventLog .. (pmLogEvent_t[ eventType+1] or "UNKNOWN")1164 pmEventLog = pmEventLog .. (pmLogEvent_t[pmLang][eventType + 1] or "UNKNOWN") 890 1165 if (eventNum == pmEventCnt) then 891 luup.variable_set(PANEL_SID, "EventLog", pmEventLog, p anel_device)1166 luup.variable_set(PANEL_SID, "EventLog", pmEventLog, pmPanelDev) 892 1167 else 893 1168 pmExpectedResponse = pmExpectedResponse .. string.char(0xA0) … … 903 1178 if (msgTot > 0) and (eventType ~= msgTot) then 904 1179 pmExpectedResponse = pmExpectedResponse .. string.char(0xA5) -- we're not done; keep them coming 1180 else 1181 pmExpectedResponse = string.char(0xA5) 905 1182 end 906 1183 if (eventType == 0x02) then … … 909 1186 local batteryStatus = string.byte(pmIncomingPdu, 9, 12) 910 1187 for i = 1, 30 do 911 local child = findChild(p anel_device, string.format("Z%02d", i))1188 local child = findChild(pmPanelDev, string.format("Z%02d", i)) 912 1189 if (child ~= nil) then 913 1190 local trip = bitw.band(zoneStatus, 2 ^ (i - 1)) > 0 and 1 or 0 … … 928 1205 929 1206 if (zoneEType ~= 0x00) then 930 debug(string.format("Event %s in Zone %02d",pmEventType_t[ zoneEType+1], eventZone))931 local child = findChild(p anel_device, string.format("Z%02d", eventZone))1207 debug(string.format("Event %s in Zone %02d",pmEventType_t[pmLang][zoneEType+1], eventZone)) 1208 local child = findChild(pmPanelDev, string.format("Z%02d", eventZone)) 932 1209 if (child == nil) then 933 1210 debug(string.format("unable to locate zone device %02d", eventZone)) … … 948 1225 949 1226 -- update status of PGM 950 local child = findChild(p anel_device, string.format("PGM"))1227 local child = findChild(pmPanelDev, string.format("PGM")) 951 1228 if (child ~= nil) then 952 1229 if (bitw.band(x10Stat1, 1) == 1) then … … 963 1240 for i = 1, 15 do 964 1241 local s = string.format("X%02d", i) 965 child = findChild(p anel_device, s)1242 child = findChild(pmPanelDev, s) 966 1243 if (child ~= nil) then 967 1244 local status = bitw.band(x10Status, 2 ^ i) > 0 and 1 or 0 … … 978 1255 if (bitw.band(sysFlags, 2) == 2) then 979 1256 sysFlagsStr = sysFlagsStr .. ",MEM" 980 updateIfNeeded(PARTITION_SID, "AlarmMemory", 1, p artition_device)1257 updateIfNeeded(PARTITION_SID, "AlarmMemory", 1, pmPartitionDev_t[1]) 981 1258 else 982 updateIfNeeded(PARTITION_SID, "AlarmMemory", 0, p artition_device)1259 updateIfNeeded(PARTITION_SID, "AlarmMemory", 0, pmPartitionDev_t[1]) 983 1260 end 984 1261 if (bitw.band(sysFlags, 4) == 4) then … … 988 1265 if (bitw.band(sysFlags, 128) == 128) then 989 1266 sysFlagsStr = sysFlagsStr .. ",ALRM" 990 if(updateIfNeeded(PARTITION_SID, "Alarm", "Active", p artition_device) == true) then991 luup.variable_set(PARTITION_SID, "LastAlarmActive", os.time(), p artition_device)1267 if(updateIfNeeded(PARTITION_SID, "Alarm", "Active", pmPartitionDev_t[1]) == true) then 1268 luup.variable_set(PARTITION_SID, "LastAlarmActive", os.time(), pmPartitionDev_t[1]) 992 1269 end 993 1270 else 994 updateIfNeeded(PARTITION_SID, "Alarm", "None", p artition_device)1271 updateIfNeeded(PARTITION_SID, "Alarm", "None", pmPartitionDev_t[1]) 995 1272 end 996 1273 local armModeNum = (pmArmed_t[sysStatus + 1] ~= nil) and 1 or 0 … … 1000 1277 if (bitw.band(sysFlags, 2 ^ i) ~= 0) then 1001 1278 if (i == 5) then 1002 s = s .. string.format("Zone %02d %s, ", eventZone, pmEventType_t[zoneEType + 1]) 1279 if (eventZone == 0xFF) then 1280 s = s .. pmEventType_t[pmLang][zoneEType + 1] .. " from Panel, " 1281 else 1282 s = s .. string.format("%s in Zone %02d, ", pmEventType_t[pmLang][zoneEType + 1], eventZone) 1283 end 1003 1284 else 1004 s = s .. pmSysStatusFlags_t[ i + 1] .. ", "1285 s = s .. pmSysStatusFlags_t[pmLang][i + 1] .. ", " 1005 1286 end 1006 1287 end 1007 1288 end 1008 1289 s = (s == "") and "Not ready" or string.sub(s, 1, string.len(s) - 2) 1009 debug(string.format("System state is %s %s",(pmSysStatus_t[ sysStatus + 1] or "UNKNOWN"), sysFlagsStr))1010 updateIfNeeded(PARTITION_SID, "VendorStatus", (pmSysStatus_t[ sysStatus + 1] or "UNKNOWN") .. sysFlagsStr, partition_device)1011 updateIfNeeded(PARTITION_SID, "VendorStatusCode", string.format("%02X%02X", sysStatus, sysFlags), p artition_device)1012 updateIfNeeded(PARTITION_SID, "VendorStatusData", s, p artition_device)1013 updateIfNeeded(PARTITION_SID, "ArmMode", armMode, p artition_device)1014 updateIfNeeded(PARTITION_SID, "ArmModeNum", armModeNum, p artition_device)1015 updateIfNeeded(PARTITION_SID, "DetailedArmMode", (pmDetailedArmMode_t[sysStatus + 1] or "UNKNOWN"), p artition_device)1290 debug(string.format("System state is %s %s",(pmSysStatus_t[pmLang][sysStatus + 1] or "UNKNOWN"), sysFlagsStr)) 1291 updateIfNeeded(PARTITION_SID, "VendorStatus", (pmSysStatus_t[pmLang][sysStatus + 1] or "UNKNOWN") .. sysFlagsStr, pmPartitionDev_t[1]) 1292 updateIfNeeded(PARTITION_SID, "VendorStatusCode", string.format("%02X%02X", sysStatus, sysFlags), pmPartitionDev_t[1]) 1293 updateIfNeeded(PARTITION_SID, "VendorStatusData", s, pmPartitionDev_t[1]) 1294 updateIfNeeded(PARTITION_SID, "ArmMode", armMode, pmPartitionDev_t[1]) 1295 updateIfNeeded(PARTITION_SID, "ArmModeNum", armModeNum, pmPartitionDev_t[1]) 1296 updateIfNeeded(PARTITION_SID, "DetailedArmMode", (pmDetailedArmMode_t[sysStatus + 1] or "UNKNOWN"), pmPartitionDev_t[1]) 1016 1297 1017 1298 elseif (eventType == 0x06) then … … 1020 1301 local zoneBypass = string.byte(pmIncomingPdu, 9, 12) 1021 1302 for i = 1, 30 do 1022 local child = findChild(p anel_device, string.format("Z%02d", i))1303 local child = findChild(pmPanelDev, string.format("Z%02d", i)) 1023 1304 if (child ~= nil) then 1024 1305 if (updateIfNeeded(SECURITY_SID, "Armed", bitw.band(zoneBypass, 2 ^ (i - 1)) > 0 and 0 or 1, child) == true) then … … 1034 1315 function pmHandlePanel() 1035 1316 local i 1036 for i = 0, 3 do 1037 local eventZone = string.byte(pmIncomingPdu, 5 + 2 * i) 1038 local logEvent = string.byte(pmIncomingPdu, 6 + 2 * i) 1039 1040 if (logEvent == 0) then 1041 return true 1042 end 1043 local s = pmLogEvent_t[logEvent + 1] .. " / " .. pmLogUser_t[eventZone + 1] 1317 local msgCnt = string.byte(pmIncomingPdu, 3) 1318 for i = 1, msgCnt do 1319 local eventZone = string.byte(pmIncomingPdu, 3 + 2 * i) 1320 local logEvent = string.byte(pmIncomingPdu, 4 + 2 * i) 1321 local s = pmLogEvent_t[pmLang][logEvent + 1] .. " / " .. pmLogUser_t[eventZone + 1] 1044 1322 debug("System message: " .. s) 1045 1323 local alarmStatus = pmPanelAlarmType_t[logEvent] or "None" 1046 1324 local troubleStatus = pmPanelTroubleType_t[logEvent] or "None" 1047 luup.variable_set(PANEL_SID, "PanelStatusCode", string.format("%02X", logEvent), panel_device) 1048 luup.variable_set(PANEL_SID, "PanelStatusData", s, panel_device) 1049 luup.variable_set(PANEL_SID, "PanelAlarmType", alarmStatus, panel_device) 1050 luup.variable_set(PANEL_SID, "PanelTroubleType", troubleStatus, panel_device) 1051 --luup.variable_set(PARTITION_SID, "LastUser", pmLogUser_t[eventZone + 1], partition_device) 1325 luup.variable_set(PANEL_SID, "PanelStatusCode", string.format("%02X", logEvent), pmPanelDev) 1326 luup.variable_set(PANEL_SID, "PanelStatusData", s, pmPanelDev) 1327 luup.variable_set(PANEL_SID, "PanelAlarmType", alarmStatus, pmPanelDev) 1328 luup.variable_set(PANEL_SID, "PanelTroubleType", troubleStatus, pmPanelDev) 1329 --luup.variable_set(PARTITION_SID, "LastUser", pmLogUser_t[eventZone + 1], pmPartitionDev_t[1]) 1330 -- TODO: update siren status 1331 if (logEvent == 0x60) then -- System reset 1332 pmReadPanelSettings() 1333 end 1052 1334 end 1053 1335 return true … … 1071 1353 elseif (subType == 0x0A and string.byte(pmIncomingPdu, 5) == 0x01) then 1072 1354 debug("Enrolling PowerLink") 1073 pmSendMessage( pmSendMsg_t.MSG_ENROLL)1074 pmSendMessage( pmSendMsg_t.MSG_EXIT)1075 pmSendMessage( pmSendMsg_t.MSG_DOWNLOAD)1355 pmSendMessage("MSG_ENROLL") 1356 pmSendMessage("MSG_EXIT") 1357 pmSendMessage("MSG_DOWNLOAD") 1076 1358 pmExpectedResponse = string.char(0xAB) .. pmExpectedResponse 1077 1359 else … … 1088 1370 debug("RequestArmMode " .. (state or "N/A")) 1089 1371 if (armPDU ~= nil) then 1090 pmSendMessage( pmSendMsg_t.MSG_ARM, { arm = string.char(armPDU), pin = pinPDU })1372 pmSendMessage("MSG_ARM", { arm = string.char(armPDU), pin = pinPDU }) 1091 1373 else 1092 1374 debug(string.format("RequestArmMode invalid state requested " .. (state or "N/A"))) … … 1100 1382 if (pmPowerlinkMode == true) then 1101 1383 RequestArmMode(DetailedArmMode, pmPincode_t[1]) 1384 elseif (DetailedArmMode == "Stay") or (DetailedArmMode == "Armed") then 1385 -- TODO: check system setting whether this mode is enabled 1386 RequestArmMode(DetailedArmMode, string.char(0, 0)) 1102 1387 else 1103 1388 pmMessage("RequestQuickArmMode only supported in Powerlink mode.", 2) … … 1107 1392 -- SetArmed 1108 1393 function SetArmed(device, newArmedValue) 1109 luup.variable_set(SECURITY_SID, "Armed", newArmedValue, device) 1394 if (pmPowerlinkMode == true) then 1395 local zone = tonumber(string.sub(luup.devices[device].id, 2)) 1396 local bypass = string.format("%08X", 2 ^ (zone - 1)) 1397 local bypassStr = "" 1398 for i = 0, 3 do 1399 bypassStr = bypassStr .. string.char("0x" .. string.sub(bypass, 7 - i * 2, 8 - i * 2)) 1400 end 1401 if (newArmedValue == "1") then 1402 pmSendMessage("MSG_BYPASSDIS", { pin = pmPincode_t[1], bypass = bypassStr }) 1403 elseif (newArmedValue == "0") then 1404 pmSendMessage("MSG_BYPASSEN", { pin = pmPincode_t[1], bypass = bypassStr }) 1405 end 1406 pmSendMessage("MSG_STATUS") -- request status to check success and update variable 1407 else 1408 luup.variable_set(SECURITY_SID, "Armed", newArmedValue, device) 1409 end 1110 1410 end 1111 1411 … … 1117 1417 if (DeviceID ~= nil) then 1118 1418 local s = (DeviceID == 0) and "PGM" or string.format("X%02d", DeviceID) 1119 local child = findChild(p anel_device, s)1419 local child = findChild(pmPanelDev, s) 1120 1420 if (child == nil) then 1121 1421 debug(string.format("Unable to locate device X%02d", DeviceID)) … … 1132 1432 debug("Turn X10 device on/off (" .. onoff .. "/" .. device_nr ..")") 1133 1433 luup.variable_set(X10DEVICE_SID, "Target", onoff, device) 1134 pmSendMessage( pmSendMsg_t.MSG_X10PGM, { cmd = string.char(onoff), device = x10dev })1434 pmSendMessage("MSG_X10PGM", { cmd = string.char(onoff), device = x10dev }) 1135 1435 -- If it went OK, we will receive an A5 status from the PowerMax, which will update the X10 status 1136 1436 end … … 1176 1476 luup.variable_set(X10DEVICEDIM_SID, "LoadLevelStatus", current, device) -- TODO: only after ACK 1177 1477 local x10dev = string.char(tonumber(string.sub(device_nr, 3, 4),16)) .. string.char(tonumber(string.sub(device_nr, 1, 2),16)) 1178 pmSendMessage( pmSendMsg_t.MSG_X10PGM, { cmd = string.char(cmd), device = x10dev })1179 pmSendMessage( pmSendMsg_t.MSG_X10PGM, { cmd = string.char(cmd), device = x10dev }) -- send it twice (step by 10%)1478 pmSendMessage("MSG_X10PGM", { cmd = string.char(cmd), device = x10dev }) 1479 pmSendMessage("MSG_X10PGM", { cmd = string.char(cmd), device = x10dev }) -- send it twice (step by 10%) 1180 1480 end 1181 1481 end … … 1204 1504 debug("GetEventLog") 1205 1505 luup.variable_set(PANEL_SID, "EventLog", "", device) 1206 pmSendMessage( pmSendMsg_t.MSG_EVENTLOG, { pin = pmGetPin(PINCode) })1506 pmSendMessage("MSG_EVENTLOG", { pin = pmGetPin(PINCode) }) 1207 1507 end 1208 1508 … … 1213 1513 t.year=t.year - 2000 1214 1514 -- Does not work on all Powermax models 1215 local timePdu = string.char(t. min, t.hour, t.day, t.month, t.year)1216 pmSendMessage( pmSendMsg_t.MSG_SETTIME, { time = timePdu })1515 local timePdu = string.char(t.sec, t.min, t.hour, t.day, t.month, t.year) 1516 pmSendMessage("MSG_SETTIME", { time = timePdu }) 1217 1517 end 1218 1518 … … 1222 1522 local bypassOn = 0 1223 1523 for i = 1, 30 do 1224 local child = findChild(p anel_device, string.format("Z%02d", i))1524 local child = findChild(pmPanelDev, string.format("Z%02d", i)) 1225 1525 if (child ~= nil) then 1226 1526 local armed = tonumber(luup.variable_get(SECURITY_SID, "Armed", child) or 0) … … 1237 1537 bypassStr = bypassStr .. string.char("0x" .. string.sub(str, 7 - i * 2, 8 - i * 2)) 1238 1538 end 1239 pmSendMessage( pmSendMsg_t.MSG_BYPASSEN, { pin = pmGetPin(PINCode), bypass = bypassStr })1539 pmSendMessage("MSG_BYPASSEN", { pin = pmGetPin(PINCode), bypass = bypassStr }) 1240 1540 end 1241 1541 … … 1245 1545 local bypassOff = 0 1246 1546 for i = 1, 30 do 1247 local child = findChild(p anel_device, string.format("Z%02d", i))1547 local child = findChild(pmPanelDev, string.format("Z%02d", i)) 1248 1548 if (child ~= nil) then 1249 1549 local armed = tonumber(luup.variable_get(SECURITY_SID, "Armed", child) or 0) … … 1260 1560 bypassStr = bypassStr .. string.char("0x" .. string.sub(str, 7 - i * 2, 8 - i * 2)) 1261 1561 end 1262 pmSendMessage( pmSendMsg_t.MSG_BYPASSDIS, { pin = pmGetPin(PINCode), bypass = bypassStr })1263 end 1562 pmSendMessage("MSG_BYPASSDIS", { pin = pmGetPin(PINCode), bypass = bypassStr }) 1563 end
Note: See TracChangeset
for help on using the changeset viewer.