Now, hereās the rules file that will handle all the message decoing and populate the items. I tried to be generous with the comments, so hopefully it will explain itself.
There are a number of ālogDebugā directives in there. Just change them to ālogInfoā to see on the console what the system is doing and how it interprets your data
import java.lang.Integer
import org.eclipse.smarthome.model.script.actions.Timer
var String Confirm_ACK="6802026800020216"
var String ACK = "6802026840024216"
var String Send_NORM = "6802026840024216"
var Timer Contacts_Update_timer = null
var Timer Outputs_Update_timer = null
var int Contacts_Update_interval = 600
var int Outputs_Update_interval = 600
var String Email_receivers = "put your email here, if you want to receive mail cotifications of system events"
rule "init"
when
System started
then
//populate the tems with some "safe" default values on system startup before they get initialized from the persistence DB
sendCommand(EMA_C400MB1,255)
sendCommand(EMA_C400MB2,255)
sendCommand(EMA_C400MB3,255)
sendCommand(EMA_C400MB4,255)
sendCommand(EMA_C400MB5,255)
sendCommand(EMA_C400OB1,255)
sendCommand(EMA_C400OB2,255)
sendCommand(EMA_C400OB3,255)
sendCommand(EMA_C400OB4,255)
sendCommand(EMA_C400OB5,255)
sendCommand(EMA_C400OB6,255)
sendCommand(EMA_C400BS1,158)
sendCommand(EMA_set_unscharf,OFF)
sendCommand(EMA_set_ext_scharf, OFF)
sendCommand(EMA_set_int_scharf, OFF)
sendCommand(EMA_set_panic, OFF)
sendCommand(EMA_reset_alarm, OFF)
sendCommand(EMA_sendNORM, OFF)
sendCommand(EMA_alarm_datestring, "00.00.00 00:00:00")
sendCommand(EMA_alarm_contact, "")
sendCommand(EMA_arme_datestring, "00.00.00 00:00:00")
sendCommand(EMA_arme_contact, "")
sendCommand(EMA_armi_datestring, "00.00.00 00:00:00")
sendCommand(EMA_armi_contact, "")
sendCommand(EMA_disarm_datestring, "00.00.00 00:00:00")
sendCommand(EMA_disarm_contact, "")
end
rule "Decode C400_InputString"
when
Item EMA_C400InputString received update
then
// The Input String is the UDP message received from the Telenot Complex 400 alarm system. It sends either ACK messages, or status update messages
// for alarm contacts (both conventional and Bus based contacts) as well as other system status updates (i.e. power outages or, of course alarms)
// The messages need to be decoded and once decoded, each message needs to be acknowledged by sending a CONFIRM_ACK message, or the system will keep
// resending it until acknowledged by CONFIRM_ACK
var dec = EMA_C400InputString.state.toString
logDebug("C400_rules", "len: "+ dec.length.toString + ", str: " + dec)
var String teststr = "00000000000000000000000000"
// Test for ACK message
if (dec.substring(0,16) == "6802026840024216") {
logDebug("C400_rules: Decode: ", "Received ACK message")
logDebug("C400_rules: Send Reply: ", "Confirm_ACK "+ Confirm_ACK.toString)
sendCommand(EMA_C400OutputString, Confirm_ACK)
}
// Test for Confirm_ACK
if (dec.substring(0,16) == "6802026800020216") {
logDebug("C400_rules: Decode: ", "Received Confirm_ACK message")
logDebug("C400_rules: Send Reply: ", "Confirm_ACK "+ Confirm_ACK.toString)
sendCommand(EMA_C400OutputString, Confirm_ACK)
}
if (dec.length > 37) {
teststr = dec.substring(0,26)
}
// Test for hte status message containing the status bits for the conventional alarm contacts
// I called it the "2e2e", because that the length the record has on my system. Yours might look a bit different
//depending on the HW configuration of your C400. Just adjust the string to test against with what you're seeing in the
//MQTT messages. You might also need to adjust the positions to decode the status bytes from in that message
if (teststr.substring(0,24) == "682e2e687302222400000001") {
logDebug("C400_rules: Decode ", "Received 2e2e Input state")
logDebug("C400_rules: Message ",dec)
// Decode Contact Bytes 1-5
var String Contactbytes = dec.substring(24,34)
logDebug("C400_rules: Decode 2e2e: conventional Contacts Bytes (1-5)", Contactbytes)
// First contact Byte holds conventional alarm contacts 1 through 8 (from LSB to MSB)
var String cbyte1 = dec.substring(24,26)
var int int1 = Integer::parseInt(cbyte1,16)
logDebug("C400_rules: Decode 2e2e:","byte1: char: " + cbyte1 + ", Int: " + int1.toString)
// Second contact Byte holds conventional alarm contacts 9 through 16
var String cbyte2 = dec.substring(26,28)
var int int2 = Integer::parseInt(cbyte2,16)
logDebug("C400_rules: Decode 2e2e:","byte2: char: " + cbyte2 + ", Int: " + int2.toString)
// Third contact Byte hold system internal alarm contacts (such as system case intrusion, etc.)
var String cbyte3 = dec.substring(28,30)
var int int3 = Integer::parseInt(cbyte3,16)
logDebug("C400_rules: Decode 2e2e:","byte3: char: " + cbyte3 + ", Int: " + int3.toString)
// Fourth contact Byte holds conventional alarm contacts 17 through 24
var String cbyte4 = dec.substring(30,32)
var int int4 = Integer::parseInt(cbyte4,16)
logDebug("C400_rules: Decode 2e2e:","byte4: char: " + cbyte4 + ", Int: " + int4.toString)
// Fifth contact byte holds conventional alarm contacts 25 through 32
var String cbyte5 = dec.substring(32,34)
var int int5 = Integer::parseInt(cbyte5,16)
logDebug("C400_rules: Decode 2e2e:","byte5: char: " + cbyte5 + ", Int: " + int5.toString)
// check if there has been a change in the values (C400 sends status every 3 seconds or so),
// we don't want to spam our events bus with no change updates
if ((int1 == (EMA_C400MB1.state as DecimalType).intValue) &&
(int2 == (EMA_C400MB2.state as DecimalType).intValue) &&
(int3 == (EMA_C400MB3.state as DecimalType).intValue) &&
(int4 == (EMA_C400MB4.state as DecimalType).intValue) &&
(int5 == (EMA_C400MB5.state as DecimalType).intValue)) {
if (Contacts_Update_timer === null) {
// Start a Timer to send an update on the Bus even if there was no change for an interval specified by
// "Contacts_Update_interval" (600 seconds) just to let the Bus know that we are alive
// Slight note of caution: I have seen this code throw some null pointer exceptions during system statup at some time. I'm not sure why this might happen yet
Contacts_Update_timer = createTimer(now.plusSeconds(Contacts_Update_interval)) [|
postUpdate(EMA_C400MB1,EMA_C400MB1.state)
postUpdate(EMA_C400MB2,EMA_C400MB2.state)
postUpdate(EMA_C400MB3,EMA_C400MB3.state)
postUpdate(EMA_C400MB4,EMA_C400MB4.state)
postUpdate(EMA_C400MB5,EMA_C400MB5.state)
Contacts_Update_timer = null
]
}
// there has been a change, update the Bus (and trigger the rules to evaluate the contacts contained in those bytes)
} else {
Contacts_Update_timer = null
postUpdate(EMA_C400MB1,int1)
postUpdate(EMA_C400MB2,int2)
postUpdate(EMA_C400MB3,int3)
postUpdate(EMA_C400MB4,int4)
postUpdate(EMA_C400MB5,int5)
}
// Decode complete, send CONFIRM_ACK message
sendCommand(EMA_C400OutputString, Confirm_ACK)
logDebug("C400_rules: 2e2e Decode complete, Send Reply: ", "Confirm_ACK "+ Confirm_ACK.toString)
}
// Test for the status message containing the status bits for the bus based alarm contacts
// I called it the "3e3e", because that the length the record has on my system. Yours might look a bit different
//depending on the HW configuration of your C400. Just adjust the string to test against with what you're seeing in the
//MQTT messages.
// I don't have any Bus based contacts on my system, so there is not code to decode them. The only thing I am interested in from this message is the status byte for the system, where you can find out if it is armed, disarmed, and so on.
// Test for 3e3e Output State message
if (teststr.substring(0,24) == "683e3e687302322400050002") {
logDebug("C400_rules: Decode", "Received 3e3e Output state")
logDebug("C400_rules: Message ",dec)
// Decode Output state Bytes 1-7
var String Outputbytes = dec.substring(24,38)
logDebug("C400_rules: Decode 3e3e: Output State Bytes (1-6) + Status Byte:", Outputbytes)
// First Output State Byte
var String obyte1 = dec.substring(24,26)
var int int1 = Integer::parseInt(obyte1,16)
logDebug("C400_rules: Decode 3e3e:","byte1: char: " + obyte1 + ", Int: " + int1.toString)
// Second Output State Byte
var String obyte2 = dec.substring(26,28)
var int int2 = Integer::parseInt(obyte2,16)
logDebug("C400_rules: Decode 3e3e:","byte2: char: " + obyte2 + ", Int: " + int2.toString)
// Third Output State Byte
var String obyte3 = dec.substring(28,30)
var int int3 = Integer::parseInt(obyte3,16)
logDebug("C400_rules: Decode 3e3e:","byte3: char: " + obyte3 + ", Int: " + int3.toString)
// Fourth Output State Byte
var String obyte4 = dec.substring(30,32)
var int int4 = Integer::parseInt(obyte4,16)
logDebug("C400_rules: Decode 3e3e:","byte4: char: " + obyte4 + ", Int: " + int4.toString)
// Fifth Output State Byte
var String obyte5 = dec.substring(32,34)
var int int5 = Integer::parseInt(obyte5,16)
logDebug("C400_rules: Decode 3e3e:","byte5: char: " + obyte5 + ", Int: " + int5.toString)
// Sixth Output State Byte
var String obyte6 = dec.substring(34,36)
var int int6 = Integer::parseInt(obyte6,16)
logDebug("C400_rules: Decode 3e3e:","byte6: char: " + obyte6 + ", Int: " + int6.toString)
// Monitored Area 1 Status Byte
var String bsbyte1 = dec.substring(36,38)
var int int7 = Integer::parseInt(bsbyte1,16)
logDebug("C400_rules: Decode 3e3e:","Status byte: char: " + bsbyte1 + ", Int: " + int7.toString)
// check if there has been a change in the values (C400 sends status every 3 seconds or so),
// we don't want to spam our events bus with no change updates
if ((int1 == (EMA_C400OB1.state as DecimalType).intValue) &&
(int2 == (EMA_C400OB2.state as DecimalType).intValue) &&
(int3 == (EMA_C400OB3.state as DecimalType).intValue) &&
(int4 == (EMA_C400OB4.state as DecimalType).intValue) &&
(int5 == (EMA_C400OB5.state as DecimalType).intValue) &&
(int6 == (EMA_C400OB6.state as DecimalType).intValue) &&
(int7 == (EMA_C400BS1.state as DecimalType).intValue)) {
if (Outputs_Update_timer === null) {
// Start a Timer to send an update on the Bus even if there was no change for an interval specified by
// "Contacts_Update_interval (600 seconds)" just to let the Bus know that we are alive
// Slight note of caution: I have seen this code throw some null pointer exceptions during system statup at some time. I'm not sure why this might happen yet
Outputs_Update_timer = createTimer(now.plusSeconds(Outputs_Update_interval)) [|
postUpdate(EMA_C400OB1,EMA_C400OB1.state)
postUpdate(EMA_C400OB2,EMA_C400OB2.state)
postUpdate(EMA_C400OB3,EMA_C400OB3.state)
postUpdate(EMA_C400OB4,EMA_C400OB4.state)
postUpdate(EMA_C400OB5,EMA_C400OB5.state)
postUpdate(EMA_C400OB6,EMA_C400OB6.state)
postUpdate(EMA_C400BS1,EMA_C400BS1.state)
Outputs_Update_timer = null
]
}
// there has been a change, update the Bus (and trigger the rules to evaluate the contacts contained in those bytes)
} else {
Outputs_Update_timer = null
postUpdate(EMA_C400OB1,int1)
postUpdate(EMA_C400OB2,int2)
postUpdate(EMA_C400OB3,int3)
postUpdate(EMA_C400OB4,int4)
postUpdate(EMA_C400OB5,int5)
postUpdate(EMA_C400OB6,int6)
postUpdate(EMA_C400BS1,int7)
}
// Decode complete, send CONFIRM_ACK message
sendCommand(EMA_C400OutputString, Confirm_ACK)
logDebug("C400_rules: 3e3e Decode complete, Send Reply: ", "Confirm_ACK "+ Confirm_ACK.toString)
}
// Test for Alarm signal / alarm signal reset
if (teststr.substring(0,18) == "683c3c687302050201") {
logInfo("C400_rules: Decode", "Alarm set/clear message received")
// Identify Type of signal. "0122" indicates an alarm, "01a2" indicates an alarm reset
var int type = Integer::parseInt(dec.substring(22,26),16)
// Decode Time of the alarm occurence
var int year = Integer::parseInt(dec.substring(30,32),16)
var int month = Integer::parseInt(dec.substring(34,36),16)
var int day = Integer::parseInt(dec.substring(36,38),16)
var int hour = Integer::parseInt(dec.substring(38,40),16)
var int min = Integer::parseInt(dec.substring(40,42),16)
var int sec = Integer::parseInt(dec.substring(42,44),16)
var String contacthex = dec.substring(44,72)
var int contacthex_len = contacthex.length()
var int b = 0
var String contact = ""
while (b < contacthex_len) {
var Integer charcode = Integer::parseInt(contacthex.substring(b,2),16)
contact += String::valueOf(Character::toChars(charcode))
b=b+2
}
// extracted all the info - update items now
postUpdate(EMA_alarm_Y, year)
postUpdate(EMA_alarm_M, month)
postUpdate(EMA_alarm_D, day)
postUpdate(EMA_alarm_h, hour)
postUpdate(EMA_alarm_m, min)
postUpdate(EMA_alarm_s, sec)
var String datetime=day.toString+"."+month.toString+"."+year.toString+" "+hour.toString+":"+min.toString+":"+sec.toString
postUpdate(EMA_alarm_datestring, datetime)
postUpdate(EMA_alarm_contact, contact)
if (type=="0122") {
logInfo("C400 ALARM set", datetime + ": "+ contact)
// put code for an alarm sequence here, i.e. turn on lights, make noise.... For now, let's just send a mail
sendMail(Email_receivers, "C400 ALARM: "+ datetime, contact)
}
if (type=="01a2") {
logInfo("C400 alarm cleared", datetime + ": "+ contact)
// put code to reset the alarm here, i.e. go back to quiet
sendMail(Email_receivers, "C400 Alarm zurueckgesetzt: "+ datetime, contact)
}
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "sytem externally armed"
if (teststr.substring(0,26) == "682c2c68730205020005320161") {
logInfo("C400_rules: Decode", "Received: System externally armed")
// Decode Time of the system going armed
var int year = Integer::parseInt(dec.substring(30,32),16)
var int month = Integer::parseInt(dec.substring(34,36),16)
var int day = Integer::parseInt(dec.substring(36,38),16)
var int hour = Integer::parseInt(dec.substring(38,40),16)
var int min = Integer::parseInt(dec.substring(40,42),16)
var int sec = Integer::parseInt(dec.substring(42,44),16)
var String contacthex = dec.substring(44,72)
var int contacthex_len = contacthex.length()
var int b = 0
var String contact = ""
while (b < contacthex_len) {
var Integer charcode = Integer::parseInt(contacthex.substring(b,b+2),16)
contact += String::valueOf(Character::toChars(charcode))
b=b+2
}
// extracted all the info - update items now
postUpdate(EMA_arme_Y, year)
postUpdate(EMA_arme_M, month)
postUpdate(EMA_arme_D, day)
postUpdate(EMA_arme_h, hour)
postUpdate(EMA_arme_m, min)
postUpdate(EMA_arme_s, sec)
var String datetime=day.toString+"."+month.toString+"."+year.toString+" "+hour.toString+":"+min.toString+":"+sec.toString
postUpdate(EMA_arme_datestring, datetime)
postUpdate(EMA_arme_contact, contact)
// Do "stuff" if the system is externally armed
// For now, let's jsut send a mail
logInfo("C400_rules:", "Extern scharf: "+ datetime + ": "+ contact)
sendMail(Email_receivers, "C400 extern scharf: "+ datetime, contact)
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "sytem internally armed"
if (teststr.substring(0,26) == "682c2c68730205020005310162") {
logInfo("C400_rules: Decode", "Received: System internally armed")
// Decode Time of the system going armed
var int year = Integer::parseInt(dec.substring(30,32),16)
var int month = Integer::parseInt(dec.substring(34,36),16)
var int day = Integer::parseInt(dec.substring(36,38),16)
var int hour = Integer::parseInt(dec.substring(38,40),16)
var int min = Integer::parseInt(dec.substring(40,42),16)
var int sec = Integer::parseInt(dec.substring(42,44),16)
var String contacthex = dec.substring(44,72)
var int contacthex_len = contacthex.length()
var int b = 0
var String contact = ""
while (b < contacthex_len) {
var Integer charcode = Integer::parseInt(contacthex.substring(b,b+2),16)
contact += String::valueOf(Character::toChars(charcode))
b=b+2
}
// extracted all the info - update items now
postUpdate(EMA_armi_Y, year)
postUpdate(EMA_armi_M, month)
postUpdate(EMA_armi_D, day)
postUpdate(EMA_armi_h, hour)
postUpdate(EMA_armi_m, min)
postUpdate(EMA_armi_s, sec)
var String datetime=day.toString+"."+month.toString+"."+year.toString+" "+hour.toString+":"+min.toString+":"+sec.toString
postUpdate(EMA_armi_datestring, datetime)
postUpdate(EMA_armi_contact, contact)
// Do "stuff" if the system is internally armed
// For now, just pst an info, that the message has been decoded
logInfo("C400_rules: ","intern scharf")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "sytem disarmed"
if (teststr.substring(0,26) == "682c2c687302050200053001e1") {
logInfo("C400_rules: Decode", "Received: System disarmed")
// Decode Time of the system going disarmed
var int year = Integer::parseInt(dec.substring(30,32),16)
var int month = Integer::parseInt(dec.substring(34,36),16)
var int day = Integer::parseInt(dec.substring(36,38),16)
var int hour = Integer::parseInt(dec.substring(38,40),16)
var int min = Integer::parseInt(dec.substring(40,42),16)
var int sec = Integer::parseInt(dec.substring(42,44),16)
var String contacthex = dec.substring(44,72)
var int contacthex_len = contacthex.length()
var int b = 0
var String contact = ""
while (b < contacthex_len) {
var Integer charcode = Integer::parseInt(contacthex.substring(b,b+2),16)
contact += String::valueOf(Character::toChars(charcode))
b=b+2
}
// extracted all the info - update items now
postUpdate(EMA_disarm_Y, year)
postUpdate(EMA_disarm_M, month)
postUpdate(EMA_disarm_D, day)
postUpdate(EMA_disarm_h, hour)
postUpdate(EMA_disarm_m, min)
postUpdate(EMA_disarm_s, sec)
var String datetime=day.toString+"."+month.toString+"."+year.toString+" "+hour.toString+":"+min.toString+":"+sec.toString
postUpdate(EMA_disarm_datestring, datetime)
postUpdate(EMA_disarm_contact, contact)
// Do "stuff" if the system is disarmed
// For now, just send a mail
sendMail(Email_receivers, "C400 unscharf: "+ datetime, contact)
logInfo("C400_rules:", "unscharf: "+ datetime + ": "+ contact)
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "system intrusion detection"
if (teststr.substring(0,26) == "682c2c68730205020100100123") {
logInfo("C400_rules: Decode", "Received: System intrusion detection")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "system intrusion cleared"
if (teststr.substring(0,26) == "682c2c687302050201001001a3") {
logInfo("C400_rules: Decode", "Received: System intrusion cleared")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "battery malfunction"
if (teststr.substring(0,26) == "681a1a68730205020000140133") {
logInfo("C400_rules: Decode", "Received: System battery malfunction")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "battery malfunction cleared"
if (teststr.substring(0,26) == "681a1a687302050200001401b3") {
logInfo("C400_rules Decode", "Received: System battery malfunction cleared")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "power outage"
if (teststr.substring(0,26) == "681a1a68730205020000150132") {
logInfo("C400_rules: Decode", "Received: power outage detected")
var int year = Integer::parseInt(dec.substring(30,32),16)
var int month = Integer::parseInt(dec.substring(34,36),16)
var int day = Integer::parseInt(dec.substring(36,38),16)
var int hour = Integer::parseInt(dec.substring(38,40),16)
var int min = Integer::parseInt(dec.substring(40,42),16)
var int sec = Integer::parseInt(dec.substring(42,44),16)
var String contacthex = dec.substring(44,72)
var int contacthex_len = contacthex.length()
var int b = 0
var String contact = ""
while (b < contacthex_len) {
var Integer charcode = Integer::parseInt(contacthex.substring(b,b+2),16)
contact += String::valueOf(Character::toChars(charcode))
b=b+2
}
var String datetime=day.toString+"."+month.toString+"."+year.toString+" "+hour.toString+":"+min.toString+":"+sec.toString
sendMail(Email_receivers, "C400 Stromausfall: "+ datetime, contact)
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "power outage cleared"
if (teststr.substring(0,26) == "681a1a687302050200001501b2") {
logInfo("C400_rules: Decode", "Received: power outage detected")
var int year = Integer::parseInt(dec.substring(30,32),16)
var int month = Integer::parseInt(dec.substring(34,36),16)
var int day = Integer::parseInt(dec.substring(36,38),16)
var int hour = Integer::parseInt(dec.substring(38,40),16)
var int min = Integer::parseInt(dec.substring(40,42),16)
var int sec = Integer::parseInt(dec.substring(42,44),16)
var String contacthex = dec.substring(44,72)
var int contacthex_len = contacthex.length()
var int b = 0
var String contact = ""
while (b < contacthex_len) {
var Integer charcode = Integer::parseInt(contacthex.substring(b,b+2),16)
contact += String::valueOf(Character::toChars(charcode))
b=b+2
}
var String datetime=day.toString+"."+month.toString+"."+year.toString+" "+hour.toString+":"+min.toString+":"+sec.toString
sendMail(Email_receivers, "C400 Stromausfall behoben: "+ datetime, contact)
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "optical flasher malfunction"
if (teststr.substring(0,26) == "681a1a68730205020000130130") {
logInfo("C400_rules: Decode", "Received: optical flasher malfunction")
// Decode done, restart the normal communication flow by seding CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "optical flasher malfunction cleared"
if (teststr.substring(0,26) == "681a1a687302050200001301b0") {
logInfo("C400_rules: Decode", "Received: optical flasher malfunction cleared")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "acoustic alarm horn 1 malfuntion"
if (teststr.substring(0,26) == "681a1a68730205020000110130") {
logInfo("C400_rules: Decode", "Reiceived: signal horn 1 malfunction")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "acoustic alarm horn 1 malfuntion cleared"
if (teststr.substring(0,26) == "681a1a687302050200001101b0") {
logInfo("C400_rules: Decode", "Received: signal horn 1 malfunction cleared")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "acoustic alarm horn 2 malfuntion"
if (teststr.substring(0,26) == "681a1a68730205020000120130") {
logInfo("C400_rules: Decode", "Received: signal horn 2 malfunction")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
// Test for info message "acoustic alarm horn 2 malfuntion cleared"
if (teststr.substring(0,26) == "681a1a687302050200001201b0") {
logInfo("C400_rules: Decode", "Received: signal horn 2 malfunction cleared")
// Decode done, restart the normal communication flow by sending CONFIRM_ACK followed by SEND_NORM
sendCommand(EMA_C400OutputString, Confirm_ACK)
sendCommand(EMA_C400OutputString, Send_NORM)
}
end